diff --git a/.gn b/.gn
index b0f1756..f86b832a 100644
--- a/.gn
+++ b/.gn
@@ -43,8 +43,7 @@
   "//crypto/*",
   "//data/*",
   "//dbus/*",
-
-  #"//device/*",  # Ran into http://crbug.com/500761 adding dbus dependency
+  "//device/*",
 
   #"//extensions/*",  # Lots of errors.
   #"//gin/*",  # Easy.
@@ -107,6 +106,7 @@
   "//build/config/linux/pkg_config.gni",
   "//build/config/mac/mac_sdk.gni",
   "//build/config/posix/BUILD.gn",
+  "//build/config/sysroot.gni",
   "//build/config/win/BUILD.gn",
   "//build/config/win/visual_studio_version.gni",
   "//build/gn_helpers.py",
diff --git a/DEPS b/DEPS
index ffe59f4..d4d41eb 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': '222b30d3a84b29b72b32e639751db4e6542d5e48',
+  'skia_revision': '262a71b7f95ce98ff3dd8dba845afbd724470903',
   # 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': 'baf869df700a81846de2a0fc9e06ee7d4d1f23e0',
+  'v8_revision': '62edb0c29bcea560a375c89bd775c3ae572ad256',
   # 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.
@@ -51,11 +51,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': 'dd5c5b79333fdde7858a77d39e91cc3d30b74c9e',
+  'angle_revision': 'fc1a44a1fe23f100a3164baf90a1b1693748450b',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling build tools
   # and whatever else without interference from each other.
-  'buildtools_revision': '818123dac34899ec230840936fc15b8b2b5556f9',
+  'buildtools_revision': 'b747a9e091cb8212a62343258406eaf53a6c032e',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
@@ -67,7 +67,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling BoringSSL
   # and whatever else without interference from each other.
-  'boringssl_revision': 'fde89b43c347155798dee8b1210c2c5faabe25f8',
+  'boringssl_revision': '6d9e5a74482bb832a6b4d9ae3d20d8f10f250bbd',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling nss
   # and whatever else without interference from each other.
@@ -187,7 +187,7 @@
    Var('chromium_git') + '/webm/libvpx.git' + '@' +  '23831545a0a148a066b905c0f1e011375c97d790',
 
   'src/third_party/ffmpeg':
-   Var('chromium_git') + '/chromium/third_party/ffmpeg.git' + '@' + 'ddfb37c83df5385cb1ef0bcdb94449d69b96b9d5',
+   Var('chromium_git') + '/chromium/third_party/ffmpeg.git' + '@' + 'b5b1d0e988d68b2bba2eb2deeacf77079f70ddfa',
 
   'src/third_party/libjingle/source/talk':
     Var('chromium_git') + '/external/webrtc/trunk/talk.git' + '@' + 'b92be1202589b4530e348aca9cf2a0dcd1263c6a', # commit position 10864
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientFullScreenTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientFullScreenTest.java
index dda45ff..e15f7f8 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientFullScreenTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientFullScreenTest.java
@@ -191,7 +191,7 @@
         assertTrue(DOMUtils.isMediaPaused(getWebContentsOnUiThread(), VIDEO_ID));
 
         tapPlayButton();
-        assertTrue(DOMUtils.waitForMediaPlay(getWebContentsOnUiThread(), VIDEO_ID));
+        DOMUtils.waitForMediaPlay(getWebContentsOnUiThread(), VIDEO_ID);
     }
 
     @MediumTest
@@ -206,7 +206,7 @@
         // Play and verify that a surface view for hole punching is not created.
         // Note that VIDEO_TEST_URL contains clear video.
         tapPlayButton();
-        assertTrue(DOMUtils.waitForMediaPlay(getWebContentsOnUiThread(), VIDEO_ID));
+        DOMUtils.waitForMediaPlay(getWebContentsOnUiThread(), VIDEO_ID);
         // Wait to ensure that the surface view is not added asynchronously.
         VideoSurfaceViewUtils.waitAndAssertContainsZeroVideoHoleSurfaceViews(this,
                 mTestContainerView);
@@ -228,7 +228,7 @@
 
         // Play and verify that there is a surface view for hole punching.
         tapPlayButton();
-        assertTrue(DOMUtils.waitForMediaPlay(getWebContentsOnUiThread(), VIDEO_ID));
+        DOMUtils.waitForMediaPlay(getWebContentsOnUiThread(), VIDEO_ID);
         VideoSurfaceViewUtils.pollAndAssertContainsOneVideoHoleSurfaceView(this,
                 mTestContainerView);
 
@@ -262,7 +262,7 @@
 
         // Play and verify that there is a surface view for hole punching.
         tapPlayButton();
-        assertTrue(DOMUtils.waitForMediaPlay(getWebContentsOnUiThread(), VIDEO_ID));
+        DOMUtils.waitForMediaPlay(getWebContentsOnUiThread(), VIDEO_ID);
         VideoSurfaceViewUtils.pollAndAssertContainsOneVideoHoleSurfaceView(this,
                 mTestContainerView);
 
@@ -438,7 +438,7 @@
             throws InterruptedException {
         // We need to poll because it takes time to synchronize the state between the android
         // views and Javascript.
-        assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
+        CriteriaHelper.pollForCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 try {
@@ -450,7 +450,7 @@
                     return false;
                 }
             }
-        }));
+        });
     }
 
     private void assertKeepScreenOnActive(final View view, final boolean expected)
@@ -475,7 +475,7 @@
 
     private void assertWaitForIsFullscreen() throws InterruptedException {
         // We need to poll because the Javascript state is updated asynchronously
-        assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
+        CriteriaHelper.pollForCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 try {
@@ -485,12 +485,12 @@
                     return false;
                 }
             }
-        }));
+        });
     }
 
     private void assertWaitForIsEmbedded() throws InterruptedException {
         // We need to poll because the Javascript state is updated asynchronously
-        assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
+        CriteriaHelper.pollForCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 try {
@@ -500,7 +500,7 @@
                     return false;
                 }
             }
-        }));
+        });
         // TODO: Test that inline video is actually displayed.
     }
 
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientOnScaleChangedTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientOnScaleChangedTest.java
index 338216a1..a98fedf65 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientOnScaleChangedTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientOnScaleChangedTest.java
@@ -37,12 +37,12 @@
                                 + " minimum-scale=0.5, maximum-scale=2, user-scalable=yes\" />",
                         "testScaleUp test page body"),
                 "text/html", false);
-        assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
+        CriteriaHelper.pollForCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return mAwContents.canZoomIn();
             }
-        }));
+        });
         int callCount = mContentsClient.getOnScaleChangedHelper().getCallCount();
         ThreadUtils.runOnUiThread(new Runnable() {
             @Override
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsGarbageCollectionTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsGarbageCollectionTest.java
index 6825dc3..501ce01 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsGarbageCollectionTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsGarbageCollectionTest.java
@@ -206,9 +206,10 @@
         // catch this case.
         final long timeoutBetweenGcMs = scaleTimeout(1000);
         for (int i = 0; i < 15; ++i) {
-            if (CriteriaHelper.pollForCriteria(criteria, timeoutBetweenGcMs, CHECK_INTERVAL)) {
+            try {
+                CriteriaHelper.pollForCriteria(criteria, timeoutBetweenGcMs, CHECK_INTERVAL);
                 break;
-            } else {
+            } catch (AssertionError e) {
                 Runtime.getRuntime().gc();
             }
         }
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 4cc375d..2f9ad91 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
@@ -495,7 +495,7 @@
      * treats timeouts and exceptions as test failures automatically.
      */
     public static void poll(final Callable<Boolean> callable) throws Exception {
-        assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
+        CriteriaHelper.pollForCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 try {
@@ -505,7 +505,7 @@
                     return false;
                 }
             }
-        }, WAIT_TIMEOUT_MS, CHECK_INTERVAL));
+        }, WAIT_TIMEOUT_MS, CHECK_INTERVAL);
     }
 
     /**
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/MultipleVideosTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/MultipleVideosTest.java
index c5f8d7f..368aa092 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/MultipleVideosTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/MultipleVideosTest.java
@@ -57,7 +57,7 @@
 
         // Play the first video.
         tapFirstPlayButton();
-        assertTrue(DOMUtils.waitForMediaPlay(getWebContentsOnUiThread(), FIRST_VIDEO_ID));
+        DOMUtils.waitForMediaPlay(getWebContentsOnUiThread(), FIRST_VIDEO_ID);
 
         // Verify that there is one video hole surface.
         VideoSurfaceViewUtils.pollAndAssertContainsOneVideoHoleSurfaceView(this,
@@ -65,7 +65,7 @@
 
         // Start the second video.
         tapSecondPlayButton();
-        assertTrue(DOMUtils.waitForMediaPlay(getWebContentsOnUiThread(), SECOND_VIDEO_ID));
+        DOMUtils.waitForMediaPlay(getWebContentsOnUiThread(), SECOND_VIDEO_ID);
 
         // Verify that the first video pauses once the second video starts.
         assertFalse(DOMUtils.isMediaPaused(getWebContentsOnUiThread(), SECOND_VIDEO_ID));
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/PopupWindowTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/PopupWindowTest.java
index 80ebe074..288ed3b8 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/PopupWindowTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/PopupWindowTest.java
@@ -134,12 +134,12 @@
     // Copied from imeTest.java.
     private void assertWaitForSelectActionBarStatus(final boolean show, final ContentViewCore cvc)
             throws InterruptedException {
-        assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return show == cvc.isSelectActionBarShowing();
             }
-        }));
+        });
     }
 
     private void hideSelectActionMode(final ContentViewCore cvc) {
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/PostMessageTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/PostMessageTest.java
index c9615cc3..ec62fdb 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/PostMessageTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/PostMessageTest.java
@@ -157,13 +157,14 @@
 
     // Call on non-UI thread.
     private void expectTitle(final String title) throws Throwable {
-        assertTrue("Received title " + mAwContents.getTitle() + " while expecting " + title,
-                CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
-                    @Override
-                    public boolean isSatisfied() {
-                        return mAwContents.getTitle().equals(title);
-                    }
-                }));
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+            @Override
+            public boolean isSatisfied() {
+                updateFailureReason(
+                        "Received title " + mAwContents.getTitle() + " while expecting " + title);
+                return mAwContents.getTitle().equals(title);
+            }
+        });
     }
 
     private void loadPage(String page) throws Throwable {
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/util/JSUtils.java b/android_webview/javatests/src/org/chromium/android_webview/test/util/JSUtils.java
index c522fa80..488b318 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/util/JSUtils.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/util/JSUtils.java
@@ -28,7 +28,7 @@
             final OnEvaluateJavaScriptResultHelper onEvaluateJavaScriptResultHelper,
             final String linkId) throws Exception {
 
-        Assert.assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
+        CriteriaHelper.pollForCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 try {
@@ -42,7 +42,7 @@
                     return false;
                 }
             }
-        }, WAIT_TIMEOUT_MS, CHECK_INTERVAL));
+        }, WAIT_TIMEOUT_MS, CHECK_INTERVAL);
 
         testCase.getInstrumentation().runOnMainSync(new Runnable() {
             @Override
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/util/VideoSurfaceViewUtils.java b/android_webview/javatests/src/org/chromium/android_webview/test/util/VideoSurfaceViewUtils.java
index 2eb11c0..cd63272 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/util/VideoSurfaceViewUtils.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/util/VideoSurfaceViewUtils.java
@@ -91,7 +91,7 @@
      */
     public static void pollAndAssertContainsOneVideoHoleSurfaceView(final AwTestBase test,
             final View view) throws InterruptedException {
-        AwTestBase.assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
+        CriteriaHelper.pollForCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 try {
@@ -102,7 +102,7 @@
                 }
             }
         }, MAX_WAIT_FOR_HOLE_PUNCHING_SURFACE_ATTACHED,
-        MAX_WAIT_FOR_HOLE_PUNCHING_SURFACE_ATTACHED / 10));
+                MAX_WAIT_FOR_HOLE_PUNCHING_SURFACE_ATTACHED / 10);
     }
 
     private static int containsNumChildrenOfType(final AwTestBase test,
diff --git a/android_webview/native/aw_autofill_client.cc b/android_webview/native/aw_autofill_client.cc
index 2b2c2667..911571a 100644
--- a/android_webview/native/aw_autofill_client.cc
+++ b/android_webview/native/aw_autofill_client.cc
@@ -194,7 +194,7 @@
 }
 
 void AwAutofillClient::SuggestionSelected(JNIEnv* env,
-                                          jobject object,
+                                          const JavaParamRef<jobject>& object,
                                           jint position) {
   if (delegate_) {
     delegate_->DidAcceptSuggestion(suggestions_[position].value,
diff --git a/android_webview/native/aw_autofill_client.h b/android_webview/native/aw_autofill_client.h
index c869ddb..b4278ed 100644
--- a/android_webview/native/aw_autofill_client.h
+++ b/android_webview/native/aw_autofill_client.h
@@ -96,7 +96,9 @@
   void OnFirstUserGestureObserved() override;
   bool IsContextSecure(const GURL& form_origin) override;
 
-  void SuggestionSelected(JNIEnv* env, jobject obj, jint position);
+  void SuggestionSelected(JNIEnv* env,
+                          const base::android::JavaParamRef<jobject>& obj,
+                          jint position);
 
  private:
   AwAutofillClient(content::WebContents* web_contents);
diff --git a/android_webview/native/aw_contents.cc b/android_webview/native/aw_contents.cc
index 8ec6260..a3bcf2f 100644
--- a/android_webview/native/aw_contents.cc
+++ b/android_webview/native/aw_contents.cc
@@ -213,13 +213,14 @@
   AwContentsLifecycleNotifier::OnWebViewCreated();
 }
 
-void AwContents::SetJavaPeers(JNIEnv* env,
-                              jobject obj,
-                              jobject aw_contents,
-                              jobject web_contents_delegate,
-                              jobject contents_client_bridge,
-                              jobject io_thread_client,
-                              jobject intercept_navigation_delegate) {
+void AwContents::SetJavaPeers(
+    JNIEnv* env,
+    const JavaParamRef<jobject>& obj,
+    const JavaParamRef<jobject>& aw_contents,
+    const JavaParamRef<jobject>& web_contents_delegate,
+    const JavaParamRef<jobject>& contents_client_bridge,
+    const JavaParamRef<jobject>& io_thread_client,
+    const JavaParamRef<jobject>& intercept_navigation_delegate) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   // The |aw_content| param is technically spurious as it duplicates |obj| but
   // is passed over anyway to make the binding more explicit.
@@ -234,8 +235,8 @@
   AwContentsClientBridgeBase::Associate(web_contents_.get(),
                                         contents_client_bridge_.get());
 
-  AwContentsIoThreadClientImpl::Associate(
-      web_contents_.get(), ScopedJavaLocalRef<jobject>(env, io_thread_client));
+  AwContentsIoThreadClientImpl::Associate(web_contents_.get(),
+                                          io_thread_client);
 
   InterceptNavigationDelegate::Associate(
       web_contents_.get(),
@@ -303,8 +304,9 @@
   AwContentsLifecycleNotifier::OnWebViewDestroyed();
 }
 
-base::android::ScopedJavaLocalRef<jobject>
-AwContents::GetWebContents(JNIEnv* env, jobject obj) {
+base::android::ScopedJavaLocalRef<jobject> AwContents::GetWebContents(
+    JNIEnv* env,
+    const JavaParamRef<jobject>& obj) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   DCHECK(web_contents_);
   if (!web_contents_)
@@ -313,7 +315,7 @@
   return web_contents_->GetJavaWebContents();
 }
 
-void AwContents::Destroy(JNIEnv* env, jobject obj) {
+void AwContents::Destroy(JNIEnv* env, const JavaParamRef<jobject>& obj) {
   java_ref_.reset();
   delete this;
 }
@@ -357,7 +359,8 @@
   return base::subtle::NoBarrier_Load(&g_instance_count);
 }
 
-jlong AwContents::GetAwDrawGLViewContext(JNIEnv* env, jobject obj) {
+jlong AwContents::GetAwDrawGLViewContext(JNIEnv* env,
+                                         const JavaParamRef<jobject>& obj) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   return reinterpret_cast<intptr_t>(
       browser_view_renderer_.GetAwDrawGLViewContext());
@@ -372,7 +375,9 @@
 }
 }  // namespace
 
-void AwContents::DocumentHasImages(JNIEnv* env, jobject obj, jobject message) {
+void AwContents::DocumentHasImages(JNIEnv* env,
+                                   const JavaParamRef<jobject>& obj,
+                                   const JavaParamRef<jobject>& message) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   ScopedJavaGlobalRef<jobject> j_message;
   j_message.Reset(env, message);
@@ -392,8 +397,10 @@
 }
 }  // namespace
 
-void AwContents::GenerateMHTML(JNIEnv* env, jobject obj,
-                               jstring jpath, jobject callback) {
+void AwContents::GenerateMHTML(JNIEnv* env,
+                               const JavaParamRef<jobject>& obj,
+                               const JavaParamRef<jstring>& jpath,
+                               const JavaParamRef<jobject>& callback) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   ScopedJavaGlobalRef<jobject>* j_callback = new ScopedJavaGlobalRef<jobject>();
   j_callback->Reset(env, callback);
@@ -404,8 +411,8 @@
 }
 
 void AwContents::CreatePdfExporter(JNIEnv* env,
-                                   jobject obj,
-                                   jobject pdfExporter) {
+                                   const JavaParamRef<jobject>& obj,
+                                   const JavaParamRef<jobject>& pdfExporter) {
   pdf_exporter_.reset(
       new AwPdfExporter(env,
                         pdfExporter,
@@ -435,9 +442,10 @@
   browser_view_renderer_.SetOffscreenPreRaster(enabled);
 }
 
-void AwContents::AddVisitedLinks(JNIEnv* env,
-                                   jobject obj,
-                                   jobjectArray jvisited_links) {
+void AwContents::AddVisitedLinks(
+    JNIEnv* env,
+    const JavaParamRef<jobject>& obj,
+    const JavaParamRef<jobjectArray>& jvisited_links) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   std::vector<base::string16> visited_link_strings;
   base::android::AppendJavaStringArrayToStringVector(
@@ -503,10 +511,11 @@
 }
 
 // Invoked from Java
-void AwContents::InvokeGeolocationCallback(JNIEnv* env,
-                                           jobject obj,
-                                           jboolean value,
-                                           jstring origin) {
+void AwContents::InvokeGeolocationCallback(
+    JNIEnv* env,
+    const JavaParamRef<jobject>& obj,
+    jboolean value,
+    const JavaParamRef<jstring>& origin) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   if (pending_geolocation_prompts_.empty())
     return;
@@ -581,11 +590,10 @@
       env, j_ref.obj(), j_request.obj());
 }
 
-void AwContents::PreauthorizePermission(
-    JNIEnv* env,
-    jobject obj,
-    jstring origin,
-    jlong resources) {
+void AwContents::PreauthorizePermission(JNIEnv* env,
+                                        const JavaParamRef<jobject>& obj,
+                                        const JavaParamRef<jstring>& origin,
+                                        jlong resources) {
   permission_request_handler_->PreauthorizePermission(
       GURL(base::android::ConvertJavaStringToUTF8(env, origin)), resources);
 }
@@ -648,25 +656,28 @@
       origin, AwPermissionRequest::AwPermissionRequest::MIDISysex);
 }
 
-void AwContents::FindAllAsync(JNIEnv* env, jobject obj, jstring search_string) {
+void AwContents::FindAllAsync(JNIEnv* env,
+                              const JavaParamRef<jobject>& obj,
+                              const JavaParamRef<jstring>& search_string) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   GetFindHelper()->FindAllAsync(ConvertJavaStringToUTF16(env, search_string));
 }
 
-void AwContents::FindNext(JNIEnv* env, jobject obj, jboolean forward) {
+void AwContents::FindNext(JNIEnv* env,
+                          const JavaParamRef<jobject>& obj,
+                          jboolean forward) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   GetFindHelper()->FindNext(forward);
 }
 
-void AwContents::ClearMatches(JNIEnv* env, jobject obj) {
+void AwContents::ClearMatches(JNIEnv* env, const JavaParamRef<jobject>& obj) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   GetFindHelper()->ClearMatches();
 }
 
-void AwContents::ClearCache(
-    JNIEnv* env,
-    jobject obj,
-    jboolean include_disk_files) {
+void AwContents::ClearCache(JNIEnv* env,
+                            const JavaParamRef<jobject>& obj,
+                            jboolean include_disk_files) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   render_view_host_ext_->ClearCache();
 
@@ -764,7 +775,7 @@
 
 base::android::ScopedJavaLocalRef<jbyteArray> AwContents::GetCertificate(
     JNIEnv* env,
-    jobject obj) {
+    const JavaParamRef<jobject>& obj) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   content::NavigationEntry* entry =
       web_contents_->GetController().GetLastCommittedEntry();
@@ -785,7 +796,7 @@
 }
 
 void AwContents::RequestNewHitTestDataAt(JNIEnv* env,
-                                         jobject obj,
+                                         const JavaParamRef<jobject>& obj,
                                          jfloat x,
                                          jfloat y,
                                          jfloat touch_major) {
@@ -795,7 +806,8 @@
   render_view_host_ext_->RequestNewHitTestDataAt(touch_center, touch_area);
 }
 
-void AwContents::UpdateLastHitTestData(JNIEnv* env, jobject obj) {
+void AwContents::UpdateLastHitTestData(JNIEnv* env,
+                                       const JavaParamRef<jobject>& obj) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   if (!render_view_host_ext_->HasNewHitTestData()) return;
 
@@ -829,23 +841,33 @@
                                     img_src.obj());
 }
 
-void AwContents::OnSizeChanged(JNIEnv* env, jobject obj,
-                               int w, int h, int ow, int oh) {
+void AwContents::OnSizeChanged(JNIEnv* env,
+                               const JavaParamRef<jobject>& obj,
+                               int w,
+                               int h,
+                               int ow,
+                               int oh) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   browser_view_renderer_.OnSizeChanged(w, h);
 }
 
-void AwContents::SetViewVisibility(JNIEnv* env, jobject obj, bool visible) {
+void AwContents::SetViewVisibility(JNIEnv* env,
+                                   const JavaParamRef<jobject>& obj,
+                                   bool visible) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   browser_view_renderer_.SetViewVisibility(visible);
 }
 
-void AwContents::SetWindowVisibility(JNIEnv* env, jobject obj, bool visible) {
+void AwContents::SetWindowVisibility(JNIEnv* env,
+                                     const JavaParamRef<jobject>& obj,
+                                     bool visible) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   browser_view_renderer_.SetWindowVisibility(visible);
 }
 
-void AwContents::SetIsPaused(JNIEnv* env, jobject obj, bool paused) {
+void AwContents::SetIsPaused(JNIEnv* env,
+                             const JavaParamRef<jobject>& obj,
+                             bool paused) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   browser_view_renderer_.SetIsPaused(paused);
   ContentViewCore* cvc =
@@ -855,17 +877,21 @@
   }
 }
 
-void AwContents::OnAttachedToWindow(JNIEnv* env, jobject obj, int w, int h) {
+void AwContents::OnAttachedToWindow(JNIEnv* env,
+                                    const JavaParamRef<jobject>& obj,
+                                    int w,
+                                    int h) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   browser_view_renderer_.OnAttachedToWindow(w, h);
 }
 
-void AwContents::OnDetachedFromWindow(JNIEnv* env, jobject obj) {
+void AwContents::OnDetachedFromWindow(JNIEnv* env,
+                                      const JavaParamRef<jobject>& obj) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   browser_view_renderer_.OnDetachedFromWindow();
 }
 
-bool AwContents::IsVisible(JNIEnv* env, jobject obj) {
+bool AwContents::IsVisible(JNIEnv* env, const JavaParamRef<jobject>& obj) {
   return browser_view_renderer_.IsClientVisible();
 }
 
@@ -876,8 +902,9 @@
     Java_AwContents_detachFunctorFromView(env, obj.obj());
 }
 
-base::android::ScopedJavaLocalRef<jbyteArray>
-AwContents::GetOpaqueState(JNIEnv* env, jobject obj) {
+base::android::ScopedJavaLocalRef<jbyteArray> AwContents::GetOpaqueState(
+    JNIEnv* env,
+    const JavaParamRef<jobject>& obj) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   // Required optimization in WebViewClassic to not save any state if
   // there has been no navigations.
@@ -894,7 +921,9 @@
 }
 
 jboolean AwContents::RestoreFromOpaqueState(
-    JNIEnv* env, jobject obj, jbyteArray state) {
+    JNIEnv* env,
+    const JavaParamRef<jobject>& obj,
+    const JavaParamRef<jbyteArray>& state) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   // TODO(boliu): This copy can be optimized out if this is a performance
   // problem.
@@ -909,8 +938,8 @@
 }
 
 bool AwContents::OnDraw(JNIEnv* env,
-                        jobject obj,
-                        jobject canvas,
+                        const JavaParamRef<jobject>& obj,
+                        const JavaParamRef<jobject>& canvas,
                         jboolean is_hardware_accelerated,
                         jint scroll_x,
                         jint scroll_y,
@@ -966,18 +995,20 @@
   pending_contents_->SetDipScaleInternal(browser_view_renderer_.dip_scale());
 }
 
-void AwContents::FocusFirstNode(JNIEnv* env, jobject obj) {
+void AwContents::FocusFirstNode(JNIEnv* env, const JavaParamRef<jobject>& obj) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   web_contents_->FocusThroughTabTraversal(false);
 }
 
-void AwContents::SetBackgroundColor(JNIEnv* env, jobject obj, jint color) {
+void AwContents::SetBackgroundColor(JNIEnv* env,
+                                    const JavaParamRef<jobject>& obj,
+                                    jint color) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   render_view_host_ext_->SetBackgroundColor(color);
 }
 
 void AwContents::OnComputeScroll(JNIEnv* env,
-                                 jobject obj,
+                                 const JavaParamRef<jobject>& obj,
                                  jlong animation_time_millis) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   browser_view_renderer_.OnComputeScroll(
@@ -985,7 +1016,8 @@
       base::TimeDelta::FromMilliseconds(animation_time_millis));
 }
 
-jlong AwContents::ReleasePopupAwContents(JNIEnv* env, jobject obj) {
+jlong AwContents::ReleasePopupAwContents(JNIEnv* env,
+                                         const JavaParamRef<jobject>& obj) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   return reinterpret_cast<intptr_t>(pending_contents_.release());
 }
@@ -1047,7 +1079,9 @@
                                 overscroll_velocity.y());
 }
 
-void AwContents::SetDipScale(JNIEnv* env, jobject obj, jfloat dip_scale) {
+void AwContents::SetDipScale(JNIEnv* env,
+                             const JavaParamRef<jobject>& obj,
+                             jfloat dip_scale) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   SetDipScaleInternal(dip_scale);
 }
@@ -1056,13 +1090,16 @@
   browser_view_renderer_.SetDipScale(dip_scale);
 }
 
-void AwContents::ScrollTo(JNIEnv* env, jobject obj, jint x, jint y) {
+void AwContents::ScrollTo(JNIEnv* env,
+                          const JavaParamRef<jobject>& obj,
+                          jint x,
+                          jint y) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   browser_view_renderer_.ScrollTo(gfx::Vector2d(x, y));
 }
 
 void AwContents::SmoothScroll(JNIEnv* env,
-                              jobject obj,
+                              const JavaParamRef<jobject>& obj,
                               jint target_x,
                               jint target_y,
                               jlong duration_ms) {
@@ -1096,7 +1133,7 @@
 }
 
 jlong AwContents::CapturePicture(JNIEnv* env,
-                                 jobject obj,
+                                 const JavaParamRef<jobject>& obj,
                                  int width,
                                  int height) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
@@ -1105,7 +1142,7 @@
 }
 
 void AwContents::EnableOnNewPicture(JNIEnv* env,
-                                    jobject obj,
+                                    const JavaParamRef<jobject>& obj,
                                     jboolean enabled) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   browser_view_renderer_.EnableOnNewPicture(enabled);
@@ -1126,7 +1163,10 @@
 }  // namespace
 
 void AwContents::InsertVisualStateCallback(
-    JNIEnv* env, jobject obj, jlong request_id, jobject callback) {
+    JNIEnv* env,
+    const JavaParamRef<jobject>& obj,
+    jlong request_id,
+    const JavaParamRef<jobject>& callback) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   ScopedJavaGlobalRef<jobject>* j_callback = new ScopedJavaGlobalRef<jobject>();
   j_callback->Reset(env, callback);
@@ -1135,13 +1175,16 @@
                  base::Owned(j_callback)));
 }
 
-void AwContents::ClearView(JNIEnv* env, jobject obj) {
+void AwContents::ClearView(JNIEnv* env, const JavaParamRef<jobject>& obj) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   browser_view_renderer_.ClearView();
 }
 
-void AwContents::SetExtraHeadersForUrl(JNIEnv* env, jobject obj,
-                                       jstring url, jstring jextra_headers) {
+void AwContents::SetExtraHeadersForUrl(
+    JNIEnv* env,
+    const JavaParamRef<jobject>& obj,
+    const JavaParamRef<jstring>& url,
+    const JavaParamRef<jstring>& jextra_headers) {
   std::string extra_headers;
   if (jextra_headers)
     extra_headers = ConvertJavaStringToUTF8(env, jextra_headers);
@@ -1153,14 +1196,14 @@
 }
 
 void AwContents::SetJsOnlineProperty(JNIEnv* env,
-                                     jobject obj,
+                                     const JavaParamRef<jobject>& obj,
                                      jboolean network_up) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   render_view_host_ext_->SetJsOnlineProperty(network_up);
 }
 
 void AwContents::TrimMemory(JNIEnv* env,
-                            jobject obj,
+                            const JavaParamRef<jobject>& obj,
                             jint level,
                             jboolean visible) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
@@ -1169,10 +1212,12 @@
 
 // TODO(sgurun) add support for posting a frame whose name is known (only
 //               main frame is supported at this time, see crbug.com/389721)
-void AwContents::PostMessageToFrame(JNIEnv* env, jobject obj,
-    jstring frame_name, jstring message, jstring target_origin,
-    jintArray sent_ports) {
-
+void AwContents::PostMessageToFrame(JNIEnv* env,
+                                    const JavaParamRef<jobject>& obj,
+                                    const JavaParamRef<jstring>& frame_name,
+                                    const JavaParamRef<jstring>& message,
+                                    const JavaParamRef<jstring>& target_origin,
+                                    const JavaParamRef<jintArray>& sent_ports) {
   // Use an empty source origin for android webview.
   base::string16 source_origin;
   base::string16 j_target_origin(ConvertJavaStringToUTF16(env, target_origin));
@@ -1211,20 +1256,23 @@
   return message_port_message_filter_;
 }
 
-void AwContents::CreateMessageChannel(JNIEnv* env, jobject obj,
-    jobjectArray ports) {
-
+void AwContents::CreateMessageChannel(JNIEnv* env,
+                                      const JavaParamRef<jobject>& obj,
+                                      const JavaParamRef<jobjectArray>& ports) {
   AwMessagePortServiceImpl::GetInstance()->CreateMessageChannel(env, ports,
       GetMessagePortMessageFilter());
 }
 
-void AwContents::GrantFileSchemeAccesstoChildProcess(JNIEnv* env, jobject obj) {
+void AwContents::GrantFileSchemeAccesstoChildProcess(
+    JNIEnv* env,
+    const JavaParamRef<jobject>& obj) {
   content::ChildProcessSecurityPolicy::GetInstance()->GrantScheme(
       web_contents_->GetRenderProcessHost()->GetID(), url::kFileScheme);
 }
 
-void AwContents::ResumeLoadingCreatedPopupWebContents(JNIEnv* env,
-                                                      jobject obj) {
+void AwContents::ResumeLoadingCreatedPopupWebContents(
+    JNIEnv* env,
+    const JavaParamRef<jobject>& obj) {
   web_contents_->ResumeLoadingCreatedWebContents();
 }
 
diff --git a/android_webview/native/aw_contents.h b/android_webview/native/aw_contents.h
index af9e8819d..22fe1b18 100644
--- a/android_webview/native/aw_contents.h
+++ b/android_webview/native/aw_contents.h
@@ -86,45 +86,85 @@
   void SetOffscreenPreRaster(bool enabled);
 
   // Methods called from Java.
-  void SetJavaPeers(JNIEnv* env,
-                    jobject obj,
-                    jobject aw_contents,
-                    jobject web_contents_delegate,
-                    jobject contents_client_bridge,
-                    jobject io_thread_client,
-                    jobject intercept_navigation_delegate);
-  base::android::ScopedJavaLocalRef<jobject> GetWebContents(JNIEnv* env,
-                                                            jobject obj);
+  void SetJavaPeers(
+      JNIEnv* env,
+      const base::android::JavaParamRef<jobject>& obj,
+      const base::android::JavaParamRef<jobject>& aw_contents,
+      const base::android::JavaParamRef<jobject>& web_contents_delegate,
+      const base::android::JavaParamRef<jobject>& contents_client_bridge,
+      const base::android::JavaParamRef<jobject>& io_thread_client,
+      const base::android::JavaParamRef<jobject>&
+          intercept_navigation_delegate);
+  base::android::ScopedJavaLocalRef<jobject> GetWebContents(
+      JNIEnv* env,
+      const base::android::JavaParamRef<jobject>& obj);
 
-  void Destroy(JNIEnv* env, jobject obj);
-  void DocumentHasImages(JNIEnv* env, jobject obj, jobject message);
-  void GenerateMHTML(JNIEnv* env, jobject obj, jstring jpath, jobject callback);
-  void CreatePdfExporter(JNIEnv* env, jobject obj, jobject pdfExporter);
-  void AddVisitedLinks(JNIEnv* env, jobject obj, jobjectArray jvisited_links);
+  void Destroy(JNIEnv* env, const base::android::JavaParamRef<jobject>& obj);
+  void DocumentHasImages(JNIEnv* env,
+                         const base::android::JavaParamRef<jobject>& obj,
+                         const base::android::JavaParamRef<jobject>& message);
+  void GenerateMHTML(JNIEnv* env,
+                     const base::android::JavaParamRef<jobject>& obj,
+                     const base::android::JavaParamRef<jstring>& jpath,
+                     const base::android::JavaParamRef<jobject>& callback);
+  void CreatePdfExporter(
+      JNIEnv* env,
+      const base::android::JavaParamRef<jobject>& obj,
+      const base::android::JavaParamRef<jobject>& pdfExporter);
+  void AddVisitedLinks(
+      JNIEnv* env,
+      const base::android::JavaParamRef<jobject>& obj,
+      const base::android::JavaParamRef<jobjectArray>& jvisited_links);
   base::android::ScopedJavaLocalRef<jbyteArray> GetCertificate(
-      JNIEnv* env, jobject obj);
+      JNIEnv* env,
+      const base::android::JavaParamRef<jobject>& obj);
   void RequestNewHitTestDataAt(JNIEnv* env,
-                               jobject obj,
+                               const base::android::JavaParamRef<jobject>& obj,
                                jfloat x,
                                jfloat y,
                                jfloat touch_major);
-  void UpdateLastHitTestData(JNIEnv* env, jobject obj);
-  void OnSizeChanged(JNIEnv* env, jobject obj, int w, int h, int ow, int oh);
-  void SetViewVisibility(JNIEnv* env, jobject obj, bool visible);
-  void SetWindowVisibility(JNIEnv* env, jobject obj, bool visible);
-  void SetIsPaused(JNIEnv* env, jobject obj, bool paused);
-  void OnAttachedToWindow(JNIEnv* env, jobject obj, int w, int h);
-  void OnDetachedFromWindow(JNIEnv* env, jobject obj);
-  bool IsVisible(JNIEnv* env, jobject obj);
+  void UpdateLastHitTestData(JNIEnv* env,
+                             const base::android::JavaParamRef<jobject>& obj);
+  void OnSizeChanged(JNIEnv* env,
+                     const base::android::JavaParamRef<jobject>& obj,
+                     int w,
+                     int h,
+                     int ow,
+                     int oh);
+  void SetViewVisibility(JNIEnv* env,
+                         const base::android::JavaParamRef<jobject>& obj,
+                         bool visible);
+  void SetWindowVisibility(JNIEnv* env,
+                           const base::android::JavaParamRef<jobject>& obj,
+                           bool visible);
+  void SetIsPaused(JNIEnv* env,
+                   const base::android::JavaParamRef<jobject>& obj,
+                   bool paused);
+  void OnAttachedToWindow(JNIEnv* env,
+                          const base::android::JavaParamRef<jobject>& obj,
+                          int w,
+                          int h);
+  void OnDetachedFromWindow(JNIEnv* env,
+                            const base::android::JavaParamRef<jobject>& obj);
+  bool IsVisible(JNIEnv* env, const base::android::JavaParamRef<jobject>& obj);
   base::android::ScopedJavaLocalRef<jbyteArray> GetOpaqueState(
-      JNIEnv* env, jobject obj);
-  jboolean RestoreFromOpaqueState(JNIEnv* env, jobject obj, jbyteArray state);
-  void FocusFirstNode(JNIEnv* env, jobject obj);
-  void SetBackgroundColor(JNIEnv* env, jobject obj, jint color);
-  void OnComputeScroll(JNIEnv* env, jobject obj, jlong animation_time_millis);
+      JNIEnv* env,
+      const base::android::JavaParamRef<jobject>& obj);
+  jboolean RestoreFromOpaqueState(
+      JNIEnv* env,
+      const base::android::JavaParamRef<jobject>& obj,
+      const base::android::JavaParamRef<jbyteArray>& state);
+  void FocusFirstNode(JNIEnv* env,
+                      const base::android::JavaParamRef<jobject>& obj);
+  void SetBackgroundColor(JNIEnv* env,
+                          const base::android::JavaParamRef<jobject>& obj,
+                          jint color);
+  void OnComputeScroll(JNIEnv* env,
+                       const base::android::JavaParamRef<jobject>& obj,
+                       jlong animation_time_millis);
   bool OnDraw(JNIEnv* env,
-              jobject obj,
-              jobject canvas,
+              const base::android::JavaParamRef<jobject>& obj,
+              const base::android::JavaParamRef<jobject>& canvas,
               jboolean is_hardware_accelerated,
               jint scroll_x,
               jint scroll_y,
@@ -132,21 +172,32 @@
               jint visible_top,
               jint visible_right,
               jint visible_bottom);
-  jlong GetAwDrawGLViewContext(JNIEnv* env, jobject obj);
-  jlong CapturePicture(JNIEnv* env, jobject obj, int width, int height);
-  void EnableOnNewPicture(JNIEnv* env, jobject obj, jboolean enabled);
-  void InsertVisualStateCallback(JNIEnv* env,
-                        jobject obj,
-                        jlong request_id,
-                        jobject callback);
-  void ClearView(JNIEnv* env, jobject obj);
-  void SetExtraHeadersForUrl(JNIEnv* env, jobject obj,
-                             jstring url, jstring extra_headers);
+  jlong GetAwDrawGLViewContext(JNIEnv* env,
+                               const base::android::JavaParamRef<jobject>& obj);
+  jlong CapturePicture(JNIEnv* env,
+                       const base::android::JavaParamRef<jobject>& obj,
+                       int width,
+                       int height);
+  void EnableOnNewPicture(JNIEnv* env,
+                          const base::android::JavaParamRef<jobject>& obj,
+                          jboolean enabled);
+  void InsertVisualStateCallback(
+      JNIEnv* env,
+      const base::android::JavaParamRef<jobject>& obj,
+      jlong request_id,
+      const base::android::JavaParamRef<jobject>& callback);
+  void ClearView(JNIEnv* env, const base::android::JavaParamRef<jobject>& obj);
+  void SetExtraHeadersForUrl(
+      JNIEnv* env,
+      const base::android::JavaParamRef<jobject>& obj,
+      const base::android::JavaParamRef<jstring>& url,
+      const base::android::JavaParamRef<jstring>& extra_headers);
 
-  void InvokeGeolocationCallback(JNIEnv* env,
-                                 jobject obj,
-                                 jboolean value,
-                                 jstring origin);
+  void InvokeGeolocationCallback(
+      JNIEnv* env,
+      const base::android::JavaParamRef<jobject>& obj,
+      jboolean value,
+      const base::android::JavaParamRef<jstring>& origin);
 
   // PermissionRequestHandlerClient implementation.
   void OnPermissionRequest(base::android::ScopedJavaLocalRef<jobject> j_request,
@@ -157,10 +208,11 @@
     return permission_request_handler_.get();
   }
 
-  void PreauthorizePermission(JNIEnv* env,
-                              jobject obj,
-                              jstring origin,
-                              jlong resources);
+  void PreauthorizePermission(
+      JNIEnv* env,
+      const base::android::JavaParamRef<jobject>& obj,
+      const base::android::JavaParamRef<jstring>& origin,
+      jlong resources);
 
   // AwBrowserPermissionRequestDelegate implementation.
   void RequestProtectedMediaIdentifierPermission(
@@ -178,9 +230,14 @@
   void CancelMIDISysexPermissionRequests(const GURL& origin) override;
 
   // Find-in-page API and related methods.
-  void FindAllAsync(JNIEnv* env, jobject obj, jstring search_string);
-  void FindNext(JNIEnv* env, jobject obj, jboolean forward);
-  void ClearMatches(JNIEnv* env, jobject obj);
+  void FindAllAsync(JNIEnv* env,
+                    const base::android::JavaParamRef<jobject>& obj,
+                    const base::android::JavaParamRef<jstring>& search_string);
+  void FindNext(JNIEnv* env,
+                const base::android::JavaParamRef<jobject>& obj,
+                jboolean forward);
+  void ClearMatches(JNIEnv* env,
+                    const base::android::JavaParamRef<jobject>& obj);
   FindHelper* GetFindHelper();
 
   // Per WebView Cookie Policy
@@ -218,33 +275,58 @@
   void ParentDrawConstraintsUpdated(
       const ParentCompositorDrawConstraints& draw_constraints) override {}
 
-  void ClearCache(JNIEnv* env, jobject obj, jboolean include_disk_files);
+  void ClearCache(JNIEnv* env,
+                  const base::android::JavaParamRef<jobject>& obj,
+                  jboolean include_disk_files);
   void SetPendingWebContentsForPopup(scoped_ptr<content::WebContents> pending);
-  jlong ReleasePopupAwContents(JNIEnv* env, jobject obj);
+  jlong ReleasePopupAwContents(JNIEnv* env,
+                               const base::android::JavaParamRef<jobject>& obj);
 
-  void ScrollTo(JNIEnv* env, jobject obj, jint x, jint y);
+  void ScrollTo(JNIEnv* env,
+                const base::android::JavaParamRef<jobject>& obj,
+                jint x,
+                jint y);
   void SmoothScroll(JNIEnv* env,
-                    jobject obj,
+                    const base::android::JavaParamRef<jobject>& obj,
                     jint target_x,
                     jint target_y,
                     jlong duration_ms);
-  void SetDipScale(JNIEnv* env, jobject obj, jfloat dip_scale);
+  void SetDipScale(JNIEnv* env,
+                   const base::android::JavaParamRef<jobject>& obj,
+                   jfloat dip_scale);
   void SetSaveFormData(bool enabled);
 
   // Sets the java client
   void SetAwAutofillClient(jobject client);
 
-  void SetJsOnlineProperty(JNIEnv* env, jobject obj, jboolean network_up);
-  void TrimMemory(JNIEnv* env, jobject obj, jint level, jboolean visible);
+  void SetJsOnlineProperty(JNIEnv* env,
+                           const base::android::JavaParamRef<jobject>& obj,
+                           jboolean network_up);
+  void TrimMemory(JNIEnv* env,
+                  const base::android::JavaParamRef<jobject>& obj,
+                  jint level,
+                  jboolean visible);
 
   scoped_refptr<AwMessagePortMessageFilter> GetMessagePortMessageFilter();
-  void PostMessageToFrame(JNIEnv* env, jobject obj, jstring frame_id,
-      jstring message, jstring target_origin, jintArray sent_ports);
-  void CreateMessageChannel(JNIEnv* env, jobject obj, jobjectArray ports);
+  void PostMessageToFrame(
+      JNIEnv* env,
+      const base::android::JavaParamRef<jobject>& obj,
+      const base::android::JavaParamRef<jstring>& frame_id,
+      const base::android::JavaParamRef<jstring>& message,
+      const base::android::JavaParamRef<jstring>& target_origin,
+      const base::android::JavaParamRef<jintArray>& sent_ports);
+  void CreateMessageChannel(
+      JNIEnv* env,
+      const base::android::JavaParamRef<jobject>& obj,
+      const base::android::JavaParamRef<jobjectArray>& ports);
 
-  void GrantFileSchemeAccesstoChildProcess(JNIEnv* env, jobject obj);
+  void GrantFileSchemeAccesstoChildProcess(
+      JNIEnv* env,
+      const base::android::JavaParamRef<jobject>& obj);
 
-  void ResumeLoadingCreatedPopupWebContents(JNIEnv* env, jobject obj);
+  void ResumeLoadingCreatedPopupWebContents(
+      JNIEnv* env,
+      const base::android::JavaParamRef<jobject>& obj);
 
  private:
   void InitAutofillIfNecessary(bool enabled);
diff --git a/android_webview/native/aw_contents_client_bridge.cc b/android_webview/native/aw_contents_client_bridge.cc
index 9e570af6..2dae8f5 100644
--- a/android_webview/native/aw_contents_client_bridge.cc
+++ b/android_webview/native/aw_contents_client_bridge.cc
@@ -108,8 +108,10 @@
   }
 }
 
-void AwContentsClientBridge::ProceedSslError(JNIEnv* env, jobject obj,
-                                             jboolean proceed, jint id) {
+void AwContentsClientBridge::ProceedSslError(JNIEnv* env,
+                                             const JavaRef<jobject>& obj,
+                                             jboolean proceed,
+                                             jint id) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   CertErrorCallback* callback = pending_cert_error_callbacks_.Lookup(id);
   if (!callback || callback->is_null()) {
@@ -196,17 +198,17 @@
 // chrome/browser/ui/android/ssl_client_certificate_request.cc
 void AwContentsClientBridge::ProvideClientCertificateResponse(
     JNIEnv* env,
-    jobject obj,
+    const JavaRef<jobject>& obj,
     int request_id,
-    jobjectArray encoded_chain_ref,
-    jobject private_key_ref) {
+    const JavaRef<jobjectArray>& encoded_chain_ref,
+    const JavaRef<jobject>& private_key_ref) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   content::ClientCertificateDelegate* delegate =
       pending_client_cert_request_delegates_.Lookup(request_id);
   DCHECK(delegate);
 
-  if (encoded_chain_ref == NULL || private_key_ref == NULL) {
+  if (encoded_chain_ref.is_null() || private_key_ref.is_null()) {
     LOG(ERROR) << "No client certificate selected";
     pending_client_cert_request_delegates_.Remove(request_id);
     delegate->ContinueWithCertificate(nullptr);
@@ -222,9 +224,9 @@
 
   // Convert the encoded chain to a vector of strings.
   std::vector<std::string> encoded_chain_strings;
-  if (encoded_chain_ref) {
+  if (!encoded_chain_ref.is_null()) {
     base::android::JavaArrayOfByteArrayToStringVector(
-        env, encoded_chain_ref, &encoded_chain_strings);
+        env, encoded_chain_ref.obj(), &encoded_chain_strings);
   }
 
   std::vector<base::StringPiece> encoded_chain;
@@ -241,7 +243,7 @@
 
   // Create an EVP_PKEY wrapper for the private key JNI reference.
   crypto::ScopedEVP_PKEY private_key(
-      net::android::GetOpenSSLPrivateKeyWrapper(private_key_ref));
+      net::android::GetOpenSSLPrivateKeyWrapper(private_key_ref.obj()));
   if (!private_key.get()) {
     LOG(ERROR) << "Could not create OpenSSL wrapper for private key";
     return;
@@ -341,9 +343,9 @@
 }
 
 void AwContentsClientBridge::ConfirmJsResult(JNIEnv* env,
-                                             jobject,
+                                             const JavaRef<jobject>&,
                                              int id,
-                                             jstring prompt) {
+                                             const JavaRef<jstring>& prompt) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   content::JavaScriptDialogManager::DialogClosedCallback* callback =
       pending_js_dialog_callbacks_.Lookup(id);
@@ -352,14 +354,16 @@
     return;
   }
   base::string16 prompt_text;
-  if (prompt) {
+  if (!prompt.is_null()) {
     prompt_text = ConvertJavaStringToUTF16(env, prompt);
   }
   callback->Run(true, prompt_text);
   pending_js_dialog_callbacks_.Remove(id);
 }
 
-void AwContentsClientBridge::CancelJsResult(JNIEnv*, jobject, int id) {
+void AwContentsClientBridge::CancelJsResult(JNIEnv*,
+                                            const JavaRef<jobject>&,
+                                            int id) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   content::JavaScriptDialogManager::DialogClosedCallback* callback =
       pending_js_dialog_callbacks_.Lookup(id);
diff --git a/android_webview/native/aw_contents_client_bridge.h b/android_webview/native/aw_contents_client_bridge.h
index 74f13e0..5372fb0 100644
--- a/android_webview/native/aw_contents_client_bridge.h
+++ b/android_webview/native/aw_contents_client_bridge.h
@@ -56,12 +56,21 @@
       override;
 
   // Methods called from Java.
-  void ProceedSslError(JNIEnv* env, jobject obj, jboolean proceed, jint id);
-  void ProvideClientCertificateResponse(JNIEnv* env, jobject object,
-      jint request_id, jobjectArray encoded_chain_ref,
-      jobject private_key_ref);
-  void ConfirmJsResult(JNIEnv*, jobject, int id, jstring prompt);
-  void CancelJsResult(JNIEnv*, jobject, int id);
+  void ProceedSslError(JNIEnv* env,
+                       const base::android::JavaRef<jobject>& obj,
+                       jboolean proceed,
+                       jint id);
+  void ProvideClientCertificateResponse(
+      JNIEnv* env,
+      const base::android::JavaRef<jobject>& object,
+      jint request_id,
+      const base::android::JavaRef<jobjectArray>& encoded_chain_ref,
+      const base::android::JavaRef<jobject>& private_key_ref);
+  void ConfirmJsResult(JNIEnv*,
+                       const base::android::JavaRef<jobject>&,
+                       int id,
+                       const base::android::JavaRef<jstring>& prompt);
+  void CancelJsResult(JNIEnv*, const base::android::JavaRef<jobject>&, int id);
 
  private:
   void HandleErrorInClientCertificateResponse(int id);
diff --git a/android_webview/native/aw_contents_client_bridge_unittest.cc b/android_webview/native/aw_contents_client_bridge_unittest.cc
index 5f19a52..e685d0b 100644
--- a/android_webview/native/aw_contents_client_bridge_unittest.cc
+++ b/android_webview/native/aw_contents_client_bridge_unittest.cc
@@ -129,10 +129,10 @@
   bridge_->SelectClientCertificate(
       cert_request_info_.get(),
       make_scoped_ptr(new TestClientCertificateDelegate(this)));
-  bridge_->ProvideClientCertificateResponse(env_, jbridge_.obj(),
+  bridge_->ProvideClientCertificateResponse(
+      env_, jbridge_,
       Java_MockAwContentsClientBridge_getRequestId(env_, jbridge_.obj()),
-      Java_MockAwContentsClientBridge_createTestCertChain(
-          env_, jbridge_.obj()).obj(),
+      Java_MockAwContentsClientBridge_createTestCertChain(env_, jbridge_.obj()),
       nullptr);
   base::RunLoop().RunUntilIdle();
   EXPECT_EQ(nullptr, selected_cert_);
@@ -150,8 +150,8 @@
       make_scoped_ptr(new TestClientCertificateDelegate(this)));
   int requestId =
     Java_MockAwContentsClientBridge_getRequestId(env_, jbridge_.obj());
-  bridge_->ProvideClientCertificateResponse(
-      env_, jbridge_.obj(), requestId, nullptr, nullptr);
+  bridge_->ProvideClientCertificateResponse(env_, jbridge_, requestId, nullptr,
+                                            nullptr);
   base::RunLoop().RunUntilIdle();
   EXPECT_EQ(nullptr, selected_cert_);
   EXPECT_EQ(1, cert_selected_callbacks_);
diff --git a/android_webview/native/aw_http_auth_handler.cc b/android_webview/native/aw_http_auth_handler.cc
index 700270a..8f4293b 100644
--- a/android_webview/native/aw_http_auth_handler.cc
+++ b/android_webview/native/aw_http_auth_handler.cc
@@ -38,9 +38,9 @@
 }
 
 void AwHttpAuthHandler::Proceed(JNIEnv* env,
-                                jobject obj,
-                                jstring user,
-                                jstring password) {
+                                const JavaParamRef<jobject>& obj,
+                                const JavaParamRef<jstring>& user,
+                                const JavaParamRef<jstring>& password) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   if (login_delegate_.get()) {
     login_delegate_->Proceed(ConvertJavaStringToUTF16(env, user),
@@ -49,7 +49,7 @@
   }
 }
 
-void AwHttpAuthHandler::Cancel(JNIEnv* env, jobject obj) {
+void AwHttpAuthHandler::Cancel(JNIEnv* env, const JavaParamRef<jobject>& obj) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   if (login_delegate_.get()) {
     login_delegate_->Cancel();
diff --git a/android_webview/native/aw_http_auth_handler.h b/android_webview/native/aw_http_auth_handler.h
index 79b7406e..09f6ed12 100644
--- a/android_webview/native/aw_http_auth_handler.h
+++ b/android_webview/native/aw_http_auth_handler.h
@@ -37,8 +37,11 @@
   // from AwHttpAuthHandler
   bool HandleOnUIThread(content::WebContents* web_contents) override;
 
-  void Proceed(JNIEnv* env, jobject obj, jstring username, jstring password);
-  void Cancel(JNIEnv* env, jobject obj);
+  void Proceed(JNIEnv* env,
+               const base::android::JavaParamRef<jobject>& obj,
+               const base::android::JavaParamRef<jstring>& username,
+               const base::android::JavaParamRef<jstring>& password);
+  void Cancel(JNIEnv* env, const base::android::JavaParamRef<jobject>& obj);
 
  private:
   scoped_refptr<AwLoginDelegate> login_delegate_;
diff --git a/android_webview/native/aw_message_port_service_impl.cc b/android_webview/native/aw_message_port_service_impl.cc
index cbbe282..65f7bb0 100644
--- a/android_webview/native/aw_message_port_service_impl.cc
+++ b/android_webview/native/aw_message_port_service_impl.cc
@@ -122,8 +122,12 @@
   }
 }
 
-void AwMessagePortServiceImpl::PostAppToWebMessage(JNIEnv* env, jobject obj,
-    int sender_id, jstring message, jintArray sent_ports) {
+void AwMessagePortServiceImpl::PostAppToWebMessage(
+    JNIEnv* env,
+    const JavaParamRef<jobject>& obj,
+    int sender_id,
+    const JavaParamRef<jstring>& message,
+    const JavaParamRef<jintArray>& sent_ports) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   base::string16* j_message = new base::string16;
   ConvertJavaStringToUTF16(env, message, j_message);
@@ -145,8 +149,9 @@
 // it is possible that messages are still queued in the renderer process
 // waiting for a conversion. Instead, it sends a special message with
 // a flag which indicates that this message port should be closed.
-void AwMessagePortServiceImpl::ClosePort(JNIEnv* env, jobject obj,
-    int message_port_id) {
+void AwMessagePortServiceImpl::ClosePort(JNIEnv* env,
+                                         const JavaParamRef<jobject>& obj,
+                                         int message_port_id) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   BrowserThread::PostTask(
       BrowserThread::IO,
@@ -156,8 +161,9 @@
                  message_port_id));
 }
 
-void AwMessagePortServiceImpl::ReleaseMessages(JNIEnv* env, jobject obj,
-    int message_port_id) {
+void AwMessagePortServiceImpl::ReleaseMessages(JNIEnv* env,
+                                               const JavaParamRef<jobject>& obj,
+                                               int message_port_id) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   BrowserThread::PostTask(
       BrowserThread::IO,
diff --git a/android_webview/native/aw_message_port_service_impl.h b/android_webview/native/aw_message_port_service_impl.h
index 7f42421..2ee31b46 100644
--- a/android_webview/native/aw_message_port_service_impl.h
+++ b/android_webview/native/aw_message_port_service_impl.h
@@ -42,10 +42,18 @@
   void CleanupPort(int message_port_id) override;
 
   // Methods called from Java.
-  void PostAppToWebMessage(JNIEnv* env, jobject object, int sender_id,
-      jstring message, jintArray sent_ports);
-  void ClosePort(JNIEnv* env, jobject object, int message_port_id);
-  void ReleaseMessages(JNIEnv* env, jobject object, int message_port_id);
+  void PostAppToWebMessage(
+      JNIEnv* env,
+      const base::android::JavaParamRef<jobject>& object,
+      int sender_id,
+      const base::android::JavaParamRef<jstring>& message,
+      const base::android::JavaParamRef<jintArray>& sent_ports);
+  void ClosePort(JNIEnv* env,
+                 const base::android::JavaParamRef<jobject>& object,
+                 int message_port_id);
+  void ReleaseMessages(JNIEnv* env,
+                       const base::android::JavaParamRef<jobject>& object,
+                       int message_port_id);
 
   void RemoveSentPorts(const std::vector<int>& sent_ports);
 
diff --git a/android_webview/native/aw_pdf_exporter.cc b/android_webview/native/aw_pdf_exporter.cc
index 48fa9f9..af08f1ff 100644
--- a/android_webview/native/aw_pdf_exporter.cc
+++ b/android_webview/native/aw_pdf_exporter.cc
@@ -33,9 +33,9 @@
 }
 
 void AwPdfExporter::ExportToPdf(JNIEnv* env,
-                                jobject obj,
+                                const JavaParamRef<jobject>& obj,
                                 int fd,
-                                jobject cancel_signal) {
+                                const JavaParamRef<jobject>& cancel_signal) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   printing::PrintSettings print_settings;
   InitPdfSettings(env, obj, print_settings);
diff --git a/android_webview/native/aw_pdf_exporter.h b/android_webview/native/aw_pdf_exporter.h
index f2513f8..2b44a85 100644
--- a/android_webview/native/aw_pdf_exporter.h
+++ b/android_webview/native/aw_pdf_exporter.h
@@ -31,9 +31,9 @@
   ~AwPdfExporter();
 
   void ExportToPdf(JNIEnv* env,
-                   jobject obj,
+                   const base::android::JavaParamRef<jobject>& obj,
                    int fd,
-                   jobject cancel_signal);
+                   const base::android::JavaParamRef<jobject>& cancel_signal);
 
  private:
   void InitPdfSettings(JNIEnv* env,
diff --git a/android_webview/native/aw_picture.cc b/android_webview/native/aw_picture.cc
index a46be2ca..6c98d3db 100644
--- a/android_webview/native/aw_picture.cc
+++ b/android_webview/native/aw_picture.cc
@@ -18,19 +18,21 @@
 
 AwPicture::~AwPicture() {}
 
-void AwPicture::Destroy(JNIEnv* env, jobject obj) {
+void AwPicture::Destroy(JNIEnv* env, const JavaParamRef<jobject>& obj) {
   delete this;
 }
 
-jint AwPicture::GetWidth(JNIEnv* env, jobject obj) {
+jint AwPicture::GetWidth(JNIEnv* env, const JavaParamRef<jobject>& obj) {
   return picture_->cullRect().roundOut().width();
 }
 
-jint AwPicture::GetHeight(JNIEnv* env, jobject obj) {
+jint AwPicture::GetHeight(JNIEnv* env, const JavaParamRef<jobject>& obj) {
   return picture_->cullRect().roundOut().height();
 }
 
-void AwPicture::Draw(JNIEnv* env, jobject obj, jobject canvas) {
+void AwPicture::Draw(JNIEnv* env,
+                     const JavaParamRef<jobject>& obj,
+                     const JavaParamRef<jobject>& canvas) {
   const SkIRect bounds = picture_->cullRect().roundOut();
   scoped_ptr<SoftwareCanvasHolder> canvas_holder = SoftwareCanvasHolder::Create(
       canvas, gfx::Vector2d(), gfx::Size(bounds.width(), bounds.height()),
diff --git a/android_webview/native/aw_picture.h b/android_webview/native/aw_picture.h
index fc4d1ec..bc129e5 100644
--- a/android_webview/native/aw_picture.h
+++ b/android_webview/native/aw_picture.h
@@ -23,10 +23,12 @@
   ~AwPicture();
 
   // Methods called from Java.
-  void Destroy(JNIEnv* env, jobject obj);
-  jint GetWidth(JNIEnv* env, jobject obj);
-  jint GetHeight(JNIEnv* env, jobject obj);
-  void Draw(JNIEnv* env, jobject obj, jobject canvas);
+  void Destroy(JNIEnv* env, const base::android::JavaParamRef<jobject>& obj);
+  jint GetWidth(JNIEnv* env, const base::android::JavaParamRef<jobject>& obj);
+  jint GetHeight(JNIEnv* env, const base::android::JavaParamRef<jobject>& obj);
+  void Draw(JNIEnv* env,
+            const base::android::JavaParamRef<jobject>& obj,
+            const base::android::JavaParamRef<jobject>& canvas);
 
  private:
   skia::RefPtr<SkPicture> picture_;
diff --git a/android_webview/native/aw_quota_manager_bridge_impl.cc b/android_webview/native/aw_quota_manager_bridge_impl.cc
index abf791e..d4ae0cd 100644
--- a/android_webview/native/aw_quota_manager_bridge_impl.cc
+++ b/android_webview/native/aw_quota_manager_bridge_impl.cc
@@ -180,7 +180,8 @@
 
 AwQuotaManagerBridgeImpl::~AwQuotaManagerBridgeImpl() {}
 
-void AwQuotaManagerBridgeImpl::Init(JNIEnv* env, jobject object) {
+void AwQuotaManagerBridgeImpl::Init(JNIEnv* env,
+                                    const JavaParamRef<jobject>& object) {
   java_ref_ = JavaObjectWeakGlobalRef(env, object);
 }
 
@@ -202,7 +203,9 @@
   return quota_manager;
 }
 
-void AwQuotaManagerBridgeImpl::DeleteAllData(JNIEnv* env, jobject object) {
+void AwQuotaManagerBridgeImpl::DeleteAllData(
+    JNIEnv* env,
+    const JavaParamRef<jobject>& object) {
   RunOnUIThread(base::Bind(&AwQuotaManagerBridgeImpl::DeleteAllDataOnUiThread,
                            this));
 }
@@ -222,7 +225,9 @@
 }
 
 void AwQuotaManagerBridgeImpl::DeleteOrigin(
-    JNIEnv* env, jobject object, jstring origin) {
+    JNIEnv* env,
+    const JavaParamRef<jobject>& object,
+    const JavaParamRef<jstring>& origin) {
   base::string16 origin_string(
       base::android::ConvertJavaStringToUTF16(env, origin));
   RunOnUIThread(base::Bind(&AwQuotaManagerBridgeImpl::DeleteOriginOnUiThread,
@@ -246,8 +251,9 @@
       base::Bind(&base::DoNothing));
 }
 
-void AwQuotaManagerBridgeImpl::GetOrigins(
-    JNIEnv* env, jobject object, jint callback_id) {
+void AwQuotaManagerBridgeImpl::GetOrigins(JNIEnv* env,
+                                          const JavaParamRef<jobject>& object,
+                                          jint callback_id) {
   RunOnUIThread(base::Bind(&AwQuotaManagerBridgeImpl::GetOriginsOnUiThread,
                            this,
                            callback_id));
@@ -305,8 +311,9 @@
 } // namespace
 
 void AwQuotaManagerBridgeImpl::GetUsageAndQuotaForOrigin(
-    JNIEnv* env, jobject object,
-    jstring origin,
+    JNIEnv* env,
+    const JavaParamRef<jobject>& object,
+    const JavaParamRef<jstring>& origin,
     jint callback_id,
     bool is_quota) {
   base::string16 origin_string(
diff --git a/android_webview/native/aw_quota_manager_bridge_impl.h b/android_webview/native/aw_quota_manager_bridge_impl.h
index dc7f20f3..530705d 100644
--- a/android_webview/native/aw_quota_manager_bridge_impl.h
+++ b/android_webview/native/aw_quota_manager_bridge_impl.h
@@ -37,15 +37,21 @@
       AwBrowserContext* browser_context);
 
   // Called by Java.
-  void Init(JNIEnv* env, jobject object);
-  void DeleteAllData(JNIEnv* env, jobject object);
-  void DeleteOrigin(JNIEnv* env, jobject object, jstring origin);
-  void GetOrigins(JNIEnv* env, jobject object, jint callback_id);
-  void GetUsageAndQuotaForOrigin(JNIEnv* env,
-                                 jobject object,
-                                 jstring origin,
-                                 jint callback_id,
-                                 bool is_quota);
+  void Init(JNIEnv* env, const base::android::JavaParamRef<jobject>& object);
+  void DeleteAllData(JNIEnv* env,
+                     const base::android::JavaParamRef<jobject>& object);
+  void DeleteOrigin(JNIEnv* env,
+                    const base::android::JavaParamRef<jobject>& object,
+                    const base::android::JavaParamRef<jstring>& origin);
+  void GetOrigins(JNIEnv* env,
+                  const base::android::JavaParamRef<jobject>& object,
+                  jint callback_id);
+  void GetUsageAndQuotaForOrigin(
+      JNIEnv* env,
+      const base::android::JavaParamRef<jobject>& object,
+      const base::android::JavaParamRef<jstring>& origin,
+      jint callback_id,
+      bool is_quota);
 
   typedef base::Callback<
       void(const std::vector<std::string>& /* origin */,
diff --git a/android_webview/native/aw_settings.cc b/android_webview/native/aw_settings.cc
index 753a9e1..8817abc 100644
--- a/android_webview/native/aw_settings.cc
+++ b/android_webview/native/aw_settings.cc
@@ -93,7 +93,7 @@
                                        reinterpret_cast<intptr_t>(this));
 }
 
-void AwSettings::Destroy(JNIEnv* env, jobject obj) {
+void AwSettings::Destroy(JNIEnv* env, const JavaParamRef<jobject>& obj) {
   delete this;
 }
 
@@ -108,7 +108,8 @@
   return contents->render_view_host_ext();
 }
 
-void AwSettings::ResetScrollAndScaleState(JNIEnv* env, jobject obj) {
+void AwSettings::ResetScrollAndScaleState(JNIEnv* env,
+                                          const JavaParamRef<jobject>& obj) {
   AwRenderViewHostExt* rvhe = GetAwRenderViewHostExt();
   if (!rvhe) return;
   rvhe->ResetScrollAndScaleState();
@@ -124,7 +125,8 @@
   Java_AwSettings_updateEverything(env, obj);
 }
 
-void AwSettings::UpdateEverythingLocked(JNIEnv* env, jobject obj) {
+void AwSettings::UpdateEverythingLocked(JNIEnv* env,
+                                        const JavaParamRef<jobject>& obj) {
   UpdateInitialPageScaleLocked(env, obj);
   UpdateWebkitPreferencesLocked(env, obj);
   UpdateUserAgentLocked(env, obj);
@@ -134,7 +136,8 @@
   UpdateOffscreenPreRasterLocked(env, obj);
 }
 
-void AwSettings::UpdateUserAgentLocked(JNIEnv* env, jobject obj) {
+void AwSettings::UpdateUserAgentLocked(JNIEnv* env,
+                                       const JavaParamRef<jobject>& obj) {
   if (!web_contents()) return;
 
   ScopedJavaLocalRef<jstring> str =
@@ -152,7 +155,9 @@
     controller.GetEntryAtIndex(i)->SetIsOverridingUserAgent(ua_overidden);
 }
 
-void AwSettings::UpdateWebkitPreferencesLocked(JNIEnv* env, jobject obj) {
+void AwSettings::UpdateWebkitPreferencesLocked(
+    JNIEnv* env,
+    const JavaParamRef<jobject>& obj) {
   if (!web_contents()) return;
   AwRenderViewHostExt* render_view_host_ext = GetAwRenderViewHostExt();
   if (!render_view_host_ext) return;
@@ -163,7 +168,9 @@
   render_view_host->OnWebkitPreferencesChanged();
 }
 
-void AwSettings::UpdateInitialPageScaleLocked(JNIEnv* env, jobject obj) {
+void AwSettings::UpdateInitialPageScaleLocked(
+    JNIEnv* env,
+    const JavaParamRef<jobject>& obj) {
   AwRenderViewHostExt* rvhe = GetAwRenderViewHostExt();
   if (!rvhe) return;
 
@@ -178,7 +185,9 @@
   }
 }
 
-void AwSettings::UpdateFormDataPreferencesLocked(JNIEnv* env, jobject obj) {
+void AwSettings::UpdateFormDataPreferencesLocked(
+    JNIEnv* env,
+    const JavaParamRef<jobject>& obj) {
   if (!web_contents()) return;
   AwContents* contents = AwContents::FromWebContents(web_contents());
   if (!contents) return;
@@ -186,7 +195,9 @@
   contents->SetSaveFormData(Java_AwSettings_getSaveFormDataLocked(env, obj));
 }
 
-void AwSettings::UpdateRendererPreferencesLocked(JNIEnv* env, jobject obj) {
+void AwSettings::UpdateRendererPreferencesLocked(
+    JNIEnv* env,
+    const JavaParamRef<jobject>& obj) {
   if (!web_contents()) return;
 
   bool update_prefs = false;
@@ -215,7 +226,9 @@
     host->SyncRendererPrefs();
 }
 
-void AwSettings::UpdateOffscreenPreRasterLocked(JNIEnv* env, jobject obj) {
+void AwSettings::UpdateOffscreenPreRasterLocked(
+    JNIEnv* env,
+    const JavaParamRef<jobject>& obj) {
   AwContents* contents = AwContents::FromWebContents(web_contents());
   if (contents) {
     contents->SetOffscreenPreRaster(
@@ -253,8 +266,9 @@
       env, obj, reinterpret_cast<jlong>(web_prefs));
 }
 
-void AwSettings::PopulateWebPreferencesLocked(
-    JNIEnv* env, jobject obj, jlong web_prefs_ptr) {
+void AwSettings::PopulateWebPreferencesLocked(JNIEnv* env,
+                                              const JavaParamRef<jobject>& obj,
+                                              jlong web_prefs_ptr) {
   AwRenderViewHostExt* render_view_host_ext = GetAwRenderViewHostExt();
   if (!render_view_host_ext) return;
 
diff --git a/android_webview/native/aw_settings.h b/android_webview/native/aw_settings.h
index 56b09ad..79d4f758 100644
--- a/android_webview/native/aw_settings.h
+++ b/android_webview/native/aw_settings.h
@@ -29,16 +29,33 @@
 
   // Called from Java. Methods with "Locked" suffix require that the settings
   // access lock is held during their execution.
-  void Destroy(JNIEnv* env, jobject obj);
-  void PopulateWebPreferencesLocked(JNIEnv* env, jobject obj, jlong web_prefs);
-  void ResetScrollAndScaleState(JNIEnv* env, jobject obj);
-  void UpdateEverythingLocked(JNIEnv* env, jobject obj);
-  void UpdateInitialPageScaleLocked(JNIEnv* env, jobject obj);
-  void UpdateUserAgentLocked(JNIEnv* env, jobject obj);
-  void UpdateWebkitPreferencesLocked(JNIEnv* env, jobject obj);
-  void UpdateFormDataPreferencesLocked(JNIEnv* env, jobject obj);
-  void UpdateRendererPreferencesLocked(JNIEnv* env, jobject obj);
-  void UpdateOffscreenPreRasterLocked(JNIEnv* env, jobject obj);
+  void Destroy(JNIEnv* env, const base::android::JavaParamRef<jobject>& obj);
+  void PopulateWebPreferencesLocked(
+      JNIEnv* env,
+      const base::android::JavaParamRef<jobject>& obj,
+      jlong web_prefs);
+  void ResetScrollAndScaleState(
+      JNIEnv* env,
+      const base::android::JavaParamRef<jobject>& obj);
+  void UpdateEverythingLocked(JNIEnv* env,
+                              const base::android::JavaParamRef<jobject>& obj);
+  void UpdateInitialPageScaleLocked(
+      JNIEnv* env,
+      const base::android::JavaParamRef<jobject>& obj);
+  void UpdateUserAgentLocked(JNIEnv* env,
+                             const base::android::JavaParamRef<jobject>& obj);
+  void UpdateWebkitPreferencesLocked(
+      JNIEnv* env,
+      const base::android::JavaParamRef<jobject>& obj);
+  void UpdateFormDataPreferencesLocked(
+      JNIEnv* env,
+      const base::android::JavaParamRef<jobject>& obj);
+  void UpdateRendererPreferencesLocked(
+      JNIEnv* env,
+      const base::android::JavaParamRef<jobject>& obj);
+  void UpdateOffscreenPreRasterLocked(
+      JNIEnv* env,
+      const base::android::JavaParamRef<jobject>& obj);
 
   void PopulateWebPreferences(content::WebPreferences* web_prefs);
 
diff --git a/android_webview/native/aw_web_contents_view_delegate.cc b/android_webview/native/aw_web_contents_view_delegate.cc
index 94f582aa..bc160599 100644
--- a/android_webview/native/aw_web_contents_view_delegate.cc
+++ b/android_webview/native/aw_web_contents_view_delegate.cc
@@ -43,11 +43,13 @@
   if (params.is_editable && params.selection_text.empty()) {
     content::ContentViewCore* content_view_core =
         content::ContentViewCore::FromWebContents(web_contents_);
-    if (content_view_core) {
-      content_view_core->ShowPastePopup(params.selection_start.x(),
-                                        params.selection_start.y());
+    if (content_view_core &&
+        content_view_core->ShowPastePopup(params.selection_start.x(),
+                                          params.selection_start.y())) {
+      return;
     }
   }
+  web_contents_->NotifyContextMenuClosed(content::CustomContextMenuContext());
 }
 
 }  // namespace android_webview
diff --git a/android_webview/native/permission/aw_permission_request.cc b/android_webview/native/permission/aw_permission_request.cc
index f25db3e0..27f0b5b6 100644
--- a/android_webview/native/permission/aw_permission_request.cc
+++ b/android_webview/native/permission/aw_permission_request.cc
@@ -46,7 +46,7 @@
 }
 
 void AwPermissionRequest::OnAccept(JNIEnv* env,
-                                   jobject jcaller,
+                                   const JavaParamRef<jobject>& jcaller,
                                    jboolean accept) {
   OnAcceptInternal(accept);
 }
@@ -66,7 +66,8 @@
                                          j_request.obj());
 }
 
-void AwPermissionRequest::Destroy(JNIEnv* env, jobject obj) {
+void AwPermissionRequest::Destroy(JNIEnv* env,
+                                  const JavaParamRef<jobject>& obj) {
   delete this;
 }
 
diff --git a/android_webview/native/permission/aw_permission_request.h b/android_webview/native/permission/aw_permission_request.h
index d146538..f016799 100644
--- a/android_webview/native/permission/aw_permission_request.h
+++ b/android_webview/native/permission/aw_permission_request.h
@@ -41,8 +41,10 @@
 
   // Invoked by Java peer when request is processed, |granted| indicates the
   // request was granted or not.
-  void OnAccept(JNIEnv* env, jobject jcaller, jboolean granted);
-  void Destroy(JNIEnv* env, jobject obj);
+  void OnAccept(JNIEnv* env,
+                const base::android::JavaParamRef<jobject>& jcaller,
+                jboolean granted);
+  void Destroy(JNIEnv* env, const base::android::JavaParamRef<jobject>& obj);
 
   // Return the origin which initiated the request.
   const GURL& GetOrigin();
diff --git a/ash/root_window_controller_unittest.cc b/ash/root_window_controller_unittest.cc
index e0f9ecc..cd8bcc4 100644
--- a/ash/root_window_controller_unittest.cc
+++ b/ash/root_window_controller_unittest.cc
@@ -214,13 +214,12 @@
   EXPECT_EQ("0,0 600x597",
             maximized->GetNativeView()->GetBoundsInRootWindow().ToString());
 
-  // Set fullscreen to true. In that case the 3px inset becomes invisible so
-  // the maximized window can also use the area fully.
+  // Set fullscreen to true, but maximized window's size won't change because
+  // it's not visible. see crbug.com/504299.
   fullscreen->SetFullscreen(true);
   EXPECT_EQ(root_windows[0], maximized->GetNativeView()->GetRootWindow());
-  EXPECT_EQ("0,0 600x600",
-            maximized->GetWindowBoundsInScreen().ToString());
-  EXPECT_EQ("0,0 600x600",
+  EXPECT_EQ("0,0 600x597", maximized->GetWindowBoundsInScreen().ToString());
+  EXPECT_EQ("0,0 600x597",
             maximized->GetNativeView()->GetBoundsInRootWindow().ToString());
 
   EXPECT_EQ(root_windows[0], minimized->GetNativeView()->GetRootWindow());
diff --git a/ash/shell/toplevel_window.cc b/ash/shell/toplevel_window.cc
index ab9cdc4..ef28e5d 100644
--- a/ash/shell/toplevel_window.cc
+++ b/ash/shell/toplevel_window.cc
@@ -29,9 +29,7 @@
 }  // namespace
 
 ToplevelWindow::CreateParams::CreateParams()
-    : can_resize(false),
-      can_maximize(false) {
-}
+    : can_resize(false), can_maximize(false), use_saved_placement(true) {}
 
 // static
 views::Widget* ToplevelWindow::CreateToplevelWindow(
@@ -78,7 +76,7 @@
     gfx::Rect* bounds,
     ui::WindowShowState* show_state) const {
   bool is_saved_bounds = !!saved_state;
-  if (saved_state) {
+  if (saved_state && params_.use_saved_placement) {
     *bounds = saved_state->bounds;
     *show_state = saved_state->show_state;
   } else {
diff --git a/ash/shell/toplevel_window.h b/ash/shell/toplevel_window.h
index 693bad5..19104516 100644
--- a/ash/shell/toplevel_window.h
+++ b/ash/shell/toplevel_window.h
@@ -17,6 +17,7 @@
 
     bool can_resize;
     bool can_maximize;
+    bool use_saved_placement;
   };
   static views::Widget* CreateToplevelWindow(
       const CreateParams& params);
diff --git a/ash/wm/default_state.cc b/ash/wm/default_state.cc
index bacf0356..ff2ac4e 100644
--- a/ash/wm/default_state.cc
+++ b/ash/wm/default_state.cc
@@ -5,6 +5,7 @@
 #include "ash/wm/default_state.h"
 
 #include "ash/display/window_tree_host_manager.h"
+#include "ash/root_window_controller.h"
 #include "ash/screen_util.h"
 #include "ash/shell.h"
 #include "ash/shell_window_ids.h"
@@ -17,6 +18,7 @@
 #include "ash/wm/window_util.h"
 #include "ash/wm/wm_event.h"
 #include "ash/wm/workspace/workspace_window_resizer.h"
+#include "ash/wm/workspace_controller.h"
 #include "ui/aura/client/aura_constants.h"
 #include "ui/aura/window.h"
 #include "ui/aura/window_delegate.h"
@@ -461,6 +463,15 @@
       return true;
     }
     case WM_EVENT_WORKAREA_BOUNDS_CHANGED: {
+      // Don't resize the maximized window when the desktop is covered
+      // by fullscreen window. crbug.com/504299.
+      bool in_fullscreen =
+          RootWindowController::ForWindow(window_state->window())
+              ->workspace_controller()
+              ->GetWindowState() == WORKSPACE_WINDOW_STATE_FULL_SCREEN;
+      if (in_fullscreen && window_state->IsMaximized())
+        return true;
+
       if (window_state->is_dragged() ||
           SetMaximizedOrFullscreenBounds(window_state)) {
         return true;
diff --git a/ash/wm/window_positioner.cc b/ash/wm/window_positioner.cc
index eed15a0..4a1d02e 100644
--- a/ash/wm/window_positioner.cc
+++ b/ash/wm/window_positioner.cc
@@ -60,17 +60,18 @@
   return !window_state->is_dragged() && window_state->window_position_managed();
 }
 
-// Check if a given |window| can be managed. This includes that it's state is
-// not minimized/maximized/the user has changed it's size by hand already.
-// It furthermore checks for the WindowIsManaged status.
+// Check if a given |window| can be managed. This includes that its
+// state is not minimized/maximized/fullscreen/the user has changed
+// its size by hand already. It furthermore checks for the
+// WindowIsManaged status.
 bool WindowPositionCanBeManaged(const aura::Window* window) {
   if (disable_auto_positioning)
     return false;
   const wm::WindowState* window_state = wm::GetWindowState(window);
   return window_state->window_position_managed() &&
-      !window_state->IsMinimized() &&
-      !window_state->IsMaximized() &&
-      !window_state->bounds_changed_by_user();
+         !window_state->IsMinimized() && !window_state->IsMaximized() &&
+         !window_state->IsFullscreen() &&
+         !window_state->bounds_changed_by_user();
 }
 
 // Get the work area for a given |window| in parent coordinates.
@@ -291,12 +292,13 @@
         ui::SHOW_STATE_DEFAULT;
   }
 
-  if (maximized) {
+  if (maximized || top_window_state->IsFullscreen()) {
     bool has_restore_bounds = top_window_state->HasRestoreBounds();
     if (has_restore_bounds) {
-      // For a maximized window ignore the real bounds of the top level window
-      // and use its restore bounds instead. Offset the bounds to prevent the
-      // windows from overlapping exactly when restored.
+      // For a maximized/fullscreen window ignore the real bounds of
+      // the top level window and use its restore bounds
+      // instead. Offset the bounds to prevent the windows from
+      // overlapping exactly when restored.
       *bounds_in_out = top_window_state->GetRestoreBoundsInScreen() +
           gfx::Vector2d(kMinimumWindowOffset, kMinimumWindowOffset);
     }
diff --git a/ash/wm/window_positioner_unittest.cc b/ash/wm/window_positioner_unittest.cc
index a9445eb..05067538 100644
--- a/ash/wm/window_positioner_unittest.cc
+++ b/ash/wm/window_positioner_unittest.cc
@@ -195,4 +195,39 @@
   EXPECT_EQ(show_state_out, ui::SHOW_STATE_MAXIMIZED);
 }
 
-}  // namespace
+TEST_F(WindowPositionerTest, IgnoreFullscreenInAutoRearrange) {
+  if (!SupportsHostWindowResize())
+    return;
+  // Set bigger than 1366 so that the new window is opened in normal state.
+  UpdateDisplay("1400x800");
+
+  // 1st window mimics fullscreen browser window behavior.
+  shell::ToplevelWindow::CreateParams params;
+  params.can_resize = true;
+  params.can_maximize = true;
+  views::Widget* widget1 = shell::ToplevelWindow::CreateToplevelWindow(params);
+  wm::WindowState* managed_state =
+      wm::GetWindowState(widget1->GetNativeWindow());
+  EXPECT_TRUE(managed_state->window_position_managed());
+  EXPECT_EQ("300x300", widget1->GetWindowBoundsInScreen().size().ToString());
+  widget1->SetFullscreen(true);
+  ASSERT_EQ("1400x800", widget1->GetWindowBoundsInScreen().size().ToString());
+
+  // 2nd window mimics windowed v1 app.
+  params.use_saved_placement = false;
+  views::Widget* widget2 = shell::ToplevelWindow::CreateToplevelWindow(params);
+  wm::WindowState* state_2 = wm::GetWindowState(widget2->GetNativeWindow());
+  EXPECT_TRUE(state_2->window_position_managed());
+  EXPECT_EQ("300x300", widget2->GetWindowBoundsInScreen().size().ToString());
+
+  // Restores to the original size.
+  widget1->SetFullscreen(false);
+  ASSERT_EQ("300x300", widget1->GetWindowBoundsInScreen().size().ToString());
+
+  // Closing 2nd widget triggers the rearrange logic but the 1st
+  // widget should stay in the current size.
+  widget2->CloseNow();
+  ASSERT_EQ("300x300", widget1->GetWindowBoundsInScreen().size().ToString());
+}
+
+}  // namespace ash
diff --git a/ash/wm/window_state_unittest.cc b/ash/wm/window_state_unittest.cc
index d816cf7..ecfbc6a 100644
--- a/ash/wm/window_state_unittest.cc
+++ b/ash/wm/window_state_unittest.cc
@@ -334,6 +334,35 @@
   EXPECT_TRUE(work_area.Contains(window->bounds()));
 }
 
+TEST_F(WindowStateTest, DoNotResizeMaximizedWindowInFullscreen) {
+  if (!SupportsHostWindowResize())
+    return;
+
+  scoped_ptr<aura::Window> maximized(CreateTestWindowInShellWithId(0));
+  scoped_ptr<aura::Window> fullscreen(CreateTestWindowInShellWithId(1));
+  WindowState* maximized_state = GetWindowState(maximized.get());
+  maximized_state->Maximize();
+  ASSERT_TRUE(maximized_state->IsMaximized());
+  EXPECT_EQ("0,0 800x553", maximized->GetBoundsInScreen().ToString());
+
+  // Entering fullscreen mode will not update the maximized window's size
+  // under fullscreen.
+  WMEvent fullscreen_event(WM_EVENT_FULLSCREEN);
+  WindowState* fullscreen_state = GetWindowState(fullscreen.get());
+  fullscreen_state->OnWMEvent(&fullscreen_event);
+  ASSERT_TRUE(fullscreen_state->IsFullscreen());
+  ASSERT_TRUE(maximized_state->IsMaximized());
+  EXPECT_EQ("0,0 800x553", maximized->GetBoundsInScreen().ToString());
+
+  // Updating display size will update the maximum window size.
+  UpdateDisplay("900x700");
+  EXPECT_EQ("0,0 900x700", maximized->GetBoundsInScreen().ToString());
+  fullscreen.reset();
+
+  // Exitting fullscreen will update the maximized widnow to the work area.
+  EXPECT_EQ("0,0 900x653", maximized->GetBoundsInScreen().ToString());
+}
+
 // TODO(skuhne): Add more unit test to verify the correctness for the restore
 // operation.
 
diff --git a/base/BUILD.gn b/base/BUILD.gn
index e5f3c196..6bc61d41 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -1005,6 +1005,8 @@
   output_name = "base_i18n"
   sources = [
     "i18n/base_i18n_export.h",
+    "i18n/base_i18n_switches.cc",
+    "i18n/base_i18n_switches.h",
     "i18n/bidi_line_iterator.cc",
     "i18n/bidi_line_iterator.h",
     "i18n/break_iterator.cc",
@@ -1257,6 +1259,7 @@
 
 test("base_unittests") {
   sources = [
+    "allocator/tcmalloc_unittest.cc",
     "android/application_status_listener_unittest.cc",
     "android/content_uri_utils_unittest.cc",
     "android/jni_android_unittest.cc",
diff --git a/base/allocator/BUILD.gn b/base/allocator/BUILD.gn
index ad781f8..7c94b5d 100644
--- a/base/allocator/BUILD.gn
+++ b/base/allocator/BUILD.gn
@@ -3,6 +3,7 @@
 # found in the LICENSE file.
 
 import("//build/config/allocator.gni")
+import("//build/config/compiler/compiler.gni")
 
 declare_args() {
   # Provide a way to force disable debugallocation in Debug builds,
@@ -147,8 +148,6 @@
       "$tcmalloc_dir/src/base/synchronization_profiling.h",
       "$tcmalloc_dir/src/base/sysinfo.cc",
       "$tcmalloc_dir/src/base/sysinfo.h",
-      "$tcmalloc_dir/src/base/thread_lister.c",
-      "$tcmalloc_dir/src/base/thread_lister.h",
       "$tcmalloc_dir/src/base/vdso_support.cc",
       "$tcmalloc_dir/src/base/vdso_support.h",
       "$tcmalloc_dir/src/central_freelist.cc",
@@ -175,11 +174,6 @@
       "$tcmalloc_dir/src/memory_region_map.h",
       "$tcmalloc_dir/src/page_heap.cc",
       "$tcmalloc_dir/src/page_heap.h",
-      "$tcmalloc_dir/src/profile-handler.cc",
-      "$tcmalloc_dir/src/profile-handler.h",
-      "$tcmalloc_dir/src/profiledata.cc",
-      "$tcmalloc_dir/src/profiledata.h",
-      "$tcmalloc_dir/src/profiler.cc",
       "$tcmalloc_dir/src/raw_printer.cc",
       "$tcmalloc_dir/src/raw_printer.h",
       "$tcmalloc_dir/src/sampler.cc",
@@ -239,16 +233,8 @@
         "$tcmalloc_dir/src/symbolize.h",
         "$tcmalloc_dir/src/system-alloc.cc",
         "$tcmalloc_dir/src/system-alloc.h",
-
-        # cpuprofiler
-        "$tcmalloc_dir/src/base/thread_lister.c",
-        "$tcmalloc_dir/src/base/thread_lister.h",
-        "$tcmalloc_dir/src/profile-handler.cc",
-        "$tcmalloc_dir/src/profile-handler.h",
-        "$tcmalloc_dir/src/profiledata.cc",
-        "$tcmalloc_dir/src/profiledata.h",
-        "$tcmalloc_dir/src/profiler.cc",
       ]
+
       defines += [ "PERFTOOLS_DLL_DECL=" ]
 
       configs -= [
@@ -262,6 +248,19 @@
       deps += [ ":prep_libc" ]
     }
 
+    if (enable_profiling) {
+      sources += [
+        "$tcmalloc_dir/src/base/thread_lister.c",
+        "$tcmalloc_dir/src/base/thread_lister.h",
+        "$tcmalloc_dir/src/profile-handler.cc",
+        "$tcmalloc_dir/src/profile-handler.h",
+        "$tcmalloc_dir/src/profiledata.cc",
+        "$tcmalloc_dir/src/profiledata.h",
+        "$tcmalloc_dir/src/profiler.cc",
+      ]
+      defines += [ "ENABLE_PROFILING=1" ]
+    }
+
     if (is_linux || is_android) {
       sources -= [
         "$tcmalloc_dir/src/system-alloc.h",
diff --git a/base/allocator/allocator.gyp b/base/allocator/allocator.gyp
index ae93e9e0..a49c2680 100644
--- a/base/allocator/allocator.gyp
+++ b/base/allocator/allocator.gyp
@@ -16,6 +16,10 @@
   'variables': {
     'tcmalloc_dir': '../../third_party/tcmalloc/chromium',
     'use_vtable_verify%': 0,
+    # Provide a way to force disable debugallocation in Debug builds
+    # e.g. for profiling (it's more rare to profile Debug builds,
+    # but people sometimes need to do that).
+    'disable_debugallocation%': 0,
   },
   'targets': [
     # Only executables and not libraries should depend on the
@@ -23,70 +27,82 @@
     # knows what allocator makes sense.
     {
       'target_name': 'allocator',
+      # TODO(primiano): This should be type: none for the noop cases (an empty
+      # static lib can confuse some gyp generators). Fix it once the refactoring
+      # (crbug.com/564618) bring this file to a saner state (fewer conditions).
       'type': 'static_library',
-      'direct_dependent_settings': {
-        'configurations': {
-          'Common_Base': {
-            'msvs_settings': {
-              'VCLinkerTool': {
-                'IgnoreDefaultLibraryNames': ['libcmtd.lib', 'libcmt.lib'],
-                'AdditionalDependencies': [
-                  '<(SHARED_INTERMEDIATE_DIR)/allocator/libcmt.lib'
-                ],
-              },
+      'conditions': [
+        # TODO(primiano): in next CL this should check win_use_allocator_shim.
+        # Right now that would produce a non-zero ninja diff for asan=1.
+        ['OS=="win" and component!="shared_library"', {
+          'msvs_settings': {
+            # TODO(sgk):  merge this with build/common.gypi settings
+            'VCLibrarianTool': {
+              'AdditionalOptions': ['/ignore:4006,4221'],
+            },
+            'VCLinkerTool': {
+              'AdditionalOptions': ['/ignore:4006'],
             },
           },
-        },
-        'conditions': [
-          ['OS=="win"', {
+          'dependencies': [
+            'libcmt',
+
+            # TODO(primiano): remove in next CL, not really needed.
+            '../third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
+          ],
+          'include_dirs': [
+            '.',  # TODO(primiano): remove in next CL, not really needed.
+            '../..',
+          ],
+          'sources': [
+            'allocator_shim_win.cc',
+          ],
+          'configurations': {
+            'Debug_Base': {
+              'msvs_settings': {
+                'VCCLCompilerTool': {
+                  'RuntimeLibrary': '0',
+                },
+              },
+              # TODO(primiano): remove this 'conditions' section soon. This is
+              # only for tc-malloc, which is not supported on windows. The only
+              # reason os it is to make the initial refactoring easier and
+              # a zero-diff ninja w.r.t. the current situation.
+              'conditions': [
+                ['disable_debugallocation==0', {
+                  'defines': [ 'TCMALLOC_FOR_DEBUGALLOCATION' ],
+                }],
+              ],
+            },
+          },
+          'direct_dependent_settings': {
+            'configurations': {
+              'Common_Base': {
+                'msvs_settings': {
+                  'VCLinkerTool': {
+                    'IgnoreDefaultLibraryNames': ['libcmtd.lib', 'libcmt.lib'],
+                    'AdditionalDependencies': [
+                      '<(SHARED_INTERMEDIATE_DIR)/allocator/libcmt.lib'
+                    ],
+                  },
+                },
+              },
+            },
             'defines': [
               'PERFTOOLS_DLL_DECL=',
             ],
-          }],
-        ],
-      },
-      'dependencies': [
-        '../third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
-      ],
-      'msvs_settings': {
-        # TODO(sgk):  merge this with build/common.gypi settings
-        'VCLibrarianTool': {
-          'AdditionalOptions': ['/ignore:4006,4221'],
-        },
-        'VCLinkerTool': {
-          'AdditionalOptions': ['/ignore:4006'],
-        },
-      },
-      'configurations': {
-        'Debug_Base': {
-          'msvs_settings': {
-            'VCCLCompilerTool': {
-              'RuntimeLibrary': '0',
-            },
           },
-          'variables': {
-            # Provide a way to force disable debugallocation in Debug builds,
-            # e.g. for profiling (it's more rare to profile Debug builds,
-            # but people sometimes need to do that).
-            'disable_debugallocation%': 0,
-          },
-          'conditions': [
-            ['disable_debugallocation==0', {
-              'defines': [
-                # Use debugallocation for Debug builds to catch problems early
-                # and cleanly, http://crbug.com/30715 .
-                'TCMALLOC_FOR_DEBUGALLOCATION',
-              ],
-            }],
-          ],
-        },
-      },
-      'conditions': [
+        }],  # OS=="win"
         ['use_allocator=="tcmalloc"', {
           # Disable the heap checker in tcmalloc.
           'defines': [
             'NO_HEAP_CHECK',
           ],
+          'dependencies': [
+            '../third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
+          ],
+          # The order of this include_dirs matters, as tc-malloc has its own
+          # base/ mini-fork. Do not factor these out of this conditions section.
           'include_dirs': [
             '.',
             '<(tcmalloc_dir)/src/base',
@@ -287,59 +303,66 @@
             # Included by debugallocation_shim.cc.
             '<(tcmalloc_dir)/src/debugallocation.cc',
             '<(tcmalloc_dir)/src/tcmalloc.cc',
-          ]
-        },{
-          'include_dirs': [
-            '.',
-            '../..',
           ],
-        }],
-        ['OS=="win" and component!="shared_library"', {
-          'dependencies': [
-            'libcmt',
+          'conditions': [
+            ['OS=="linux" or OS=="freebsd" or OS=="solaris" or OS=="android"', {
+              'sources!': [
+                '<(tcmalloc_dir)/src/system-alloc.h',
+              ],
+              # We enable all warnings by default, but upstream disables a few.
+              # Keep "-Wno-*" flags in sync with upstream by comparing against:
+              # http://code.google.com/p/google-perftools/source/browse/trunk/Makefile.am
+              'cflags': [
+                '-Wno-sign-compare',
+                '-Wno-unused-result',
+              ],
+              'cflags!': [
+                '-fvisibility=hidden',
+              ],
+              'link_settings': {
+                'ldflags': [
+                  # Don't let linker rip this symbol out, otherwise the heap&cpu
+                  # profilers will not initialize properly on startup.
+                  '-Wl,-uIsHeapProfilerRunning,-uProfilerStart',
+                  # Do the same for heap leak checker.
+                  '-Wl,-u_Z21InitialMallocHook_NewPKvj,-u_Z22InitialMallocHook_MMapPKvS0_jiiix,-u_Z22InitialMallocHook_SbrkPKvi',
+                  '-Wl,-u_Z21InitialMallocHook_NewPKvm,-u_Z22InitialMallocHook_MMapPKvS0_miiil,-u_Z22InitialMallocHook_SbrkPKvl',
+                  '-Wl,-u_ZN15HeapLeakChecker12IgnoreObjectEPKv,-u_ZN15HeapLeakChecker14UnIgnoreObjectEPKv',
+                ],
+              },
+            }],
+            ['profiling!=1', {
+              'sources!': [
+                # cpuprofiler
+                '<(tcmalloc_dir)/src/base/thread_lister.c',
+                '<(tcmalloc_dir)/src/base/thread_lister.h',
+                '<(tcmalloc_dir)/src/profile-handler.cc',
+                '<(tcmalloc_dir)/src/profile-handler.h',
+                '<(tcmalloc_dir)/src/profiledata.cc',
+                '<(tcmalloc_dir)/src/profiledata.h',
+                '<(tcmalloc_dir)/src/profiler.cc',
+              ],
+            }],
           ],
-          'sources': [
-            'allocator_shim_win.cc',
-          ],
-        }],
-        ['profiling!=1', {
-          'sources!': [
-            # cpuprofiler
-            '<(tcmalloc_dir)/src/base/thread_lister.c',
-            '<(tcmalloc_dir)/src/base/thread_lister.h',
-            '<(tcmalloc_dir)/src/profile-handler.cc',
-            '<(tcmalloc_dir)/src/profile-handler.h',
-            '<(tcmalloc_dir)/src/profiledata.cc',
-            '<(tcmalloc_dir)/src/profiledata.h',
-            '<(tcmalloc_dir)/src/profiler.cc',
-          ],
-        }],
-        ['OS=="linux" or OS=="freebsd" or OS=="solaris" or OS=="android"', {
-          'sources!': [
-            '<(tcmalloc_dir)/src/system-alloc.h',
-          ],
-          # We enable all warnings by default, but upstream disables a few.
-          # Keep "-Wno-*" flags in sync with upstream by comparing against:
-          # http://code.google.com/p/google-perftools/source/browse/trunk/Makefile.am
-          'cflags': [
-            '-Wno-sign-compare',
-            '-Wno-unused-result',
-          ],
-          'cflags!': [
-            '-fvisibility=hidden',
-          ],
-          'link_settings': {
-            'ldflags': [
-              # Don't let linker rip this symbol out, otherwise the heap&cpu
-              # profilers will not initialize properly on startup.
-              '-Wl,-uIsHeapProfilerRunning,-uProfilerStart',
-              # Do the same for heap leak checker.
-              '-Wl,-u_Z21InitialMallocHook_NewPKvj,-u_Z22InitialMallocHook_MMapPKvS0_jiiix,-u_Z22InitialMallocHook_SbrkPKvi',
-              '-Wl,-u_Z21InitialMallocHook_NewPKvm,-u_Z22InitialMallocHook_MMapPKvS0_miiil,-u_Z22InitialMallocHook_SbrkPKvl',
-              '-Wl,-u_ZN15HeapLeakChecker12IgnoreObjectEPKv,-u_ZN15HeapLeakChecker14UnIgnoreObjectEPKv',
-          ]},
-        }],
-        [ 'use_vtable_verify==1', {
+          'configurations': {
+            'Debug_Base': {
+              'conditions': [
+                ['disable_debugallocation==0', {
+                  'defines': [
+                    # Use debugallocation for Debug builds to catch problems
+                    # early and cleanly, http://crbug.com/30715 .
+                    'TCMALLOC_FOR_DEBUGALLOCATION',
+                  ],
+                }],
+              ],
+            },
+          },
+        }],  # use_allocator=="tcmalloc
+        # For CrOS builds with vtable verification. According to the author of
+        # crrev.com/10854031 this is used in conjuction with some other CrOS
+        # build flag, to enable verification of any allocator that uses virtual
+        # function calls.
+        ['use_vtable_verify==1', {
           'cflags': [
             '-fvtable-verify=preinit',
           ],
@@ -351,12 +374,9 @@
             }],
           ],
         }],
-      ],
-    },
+      ],  # conditions of 'allocator' target.
+    },  # 'allocator' target.
     {
-      # This library is linked in to src/base.gypi:base and allocator_unittests
-      # It can't depend on either and nothing else should depend on it - all
-      # other code should use the interfaced provided by base.
       'target_name': 'allocator_extension_thunks',
       'type': 'static_library',
       'sources': [
@@ -394,24 +414,6 @@
             },
           ],
         },
-        {
-          'target_name': 'allocator_unittests',
-          'type': 'executable',
-          'dependencies': [
-            'allocator',
-            'allocator_extension_thunks',
-            '../../testing/gtest.gyp:gtest',
-          ],
-          'include_dirs': [
-            '.',
-            '../..',
-          ],
-          'sources': [
-            '../profiler/alternate_timer.cc',
-            '../profiler/alternate_timer.h',
-            'allocator_unittest.cc',
-          ],
-        },
       ],
     }],
     ['OS=="win" and target_arch=="ia32"', {
@@ -435,24 +437,5 @@
         },
       ],
     }],
-    ['use_allocator=="tcmalloc"', {
-      'targets': [
-         {
-           'target_name': 'tcmalloc_unittest',
-           'type': 'executable',
-           'sources': [
-             'tcmalloc_unittest.cc',
-           ],
-           'include_dirs': [
-             '<(tcmalloc_dir)/src',
-             '../..',
-           ],
-           'dependencies': [
-             '../../testing/gtest.gyp:gtest',
-             'allocator',
-          ],
-        },
-      ],
-    }],
   ],
 }
diff --git a/base/allocator/allocator_unittest.cc b/base/allocator/allocator_unittest.cc
deleted file mode 100644
index a1d1ef0..0000000
--- a/base/allocator/allocator_unittest.cc
+++ /dev/null
@@ -1,245 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <algorithm>   // for min()
-
-#include "base/macros.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-// Number of bits in a size_t.
-static const int kSizeBits = 8 * sizeof(size_t);
-// The maximum size of a size_t.
-static const size_t kMaxSize = ~static_cast<size_t>(0);
-// Maximum positive size of a size_t if it were signed.
-static const size_t kMaxSignedSize = ((size_t(1) << (kSizeBits-1)) - 1);
-
-namespace {
-
-using std::min;
-
-// Fill a buffer of the specified size with a predetermined pattern
-static void Fill(unsigned char* buffer, int n) {
-  for (int i = 0; i < n; i++) {
-    buffer[i] = (i & 0xff);
-  }
-}
-
-// Check that the specified buffer has the predetermined pattern
-// generated by Fill()
-static bool Valid(unsigned char* buffer, int n) {
-  for (int i = 0; i < n; i++) {
-    if (buffer[i] != (i & 0xff)) {
-      return false;
-    }
-  }
-  return true;
-}
-
-// Check that a buffer is completely zeroed.
-static bool IsZeroed(unsigned char* buffer, int n) {
-  for (int i = 0; i < n; i++) {
-    if (buffer[i] != 0) {
-      return false;
-    }
-  }
-  return true;
-}
-
-// Check alignment
-static void CheckAlignment(void* p, int align) {
-  EXPECT_EQ(0, reinterpret_cast<uintptr_t>(p) & (align-1));
-}
-
-// Return the next interesting size/delta to check.  Returns -1 if no more.
-static int NextSize(int size) {
-  if (size < 100)
-    return size+1;
-
-  if (size < 100000) {
-    // Find next power of two
-    int power = 1;
-    while (power < size)
-      power <<= 1;
-
-    // Yield (power-1, power, power+1)
-    if (size < power-1)
-      return power-1;
-
-    if (size == power-1)
-      return power;
-
-    assert(size == power);
-    return power+1;
-  } else {
-    return -1;
-  }
-}
-
-static void TestCalloc(size_t n, size_t s, bool ok) {
-  char* p = reinterpret_cast<char*>(calloc(n, s));
-  if (!ok) {
-    EXPECT_EQ(NULL, p) << "calloc(n, s) should not succeed";
-  } else {
-    EXPECT_NE(reinterpret_cast<void*>(NULL), p) <<
-        "calloc(n, s) should succeed";
-    for (size_t i = 0; i < n*s; i++) {
-      EXPECT_EQ('\0', p[i]);
-    }
-    free(p);
-  }
-}
-
-}  // namespace
-
-//-----------------------------------------------------------------------------
-
-
-TEST(Allocators, Malloc) {
-  // Try allocating data with a bunch of alignments and sizes
-  for (int size = 1; size < 1048576; size *= 2) {
-    unsigned char* ptr = reinterpret_cast<unsigned char*>(malloc(size));
-    CheckAlignment(ptr, 2);  // Should be 2 byte aligned
-    Fill(ptr, size);
-    EXPECT_TRUE(Valid(ptr, size));
-    free(ptr);
-  }
-}
-
-TEST(Allocators, Calloc) {
-  TestCalloc(0, 0, true);
-  TestCalloc(0, 1, true);
-  TestCalloc(1, 1, true);
-  TestCalloc(1<<10, 0, true);
-  TestCalloc(1<<20, 0, true);
-  TestCalloc(0, 1<<10, true);
-  TestCalloc(0, 1<<20, true);
-  TestCalloc(1<<20, 2, true);
-  TestCalloc(2, 1<<20, true);
-  TestCalloc(1000, 1000, true);
-
-  TestCalloc(kMaxSize, 2, false);
-  TestCalloc(2, kMaxSize, false);
-  TestCalloc(kMaxSize, kMaxSize, false);
-
-  TestCalloc(kMaxSignedSize, 3, false);
-  TestCalloc(3, kMaxSignedSize, false);
-  TestCalloc(kMaxSignedSize, kMaxSignedSize, false);
-}
-
-// This makes sure that reallocing a small number of bytes in either
-// direction doesn't cause us to allocate new memory.
-TEST(Allocators, Realloc1) {
-  int start_sizes[] = { 100, 1000, 10000, 100000 };
-  int deltas[] = { 1, -2, 4, -8, 16, -32, 64, -128 };
-
-  for (int s = 0; s < sizeof(start_sizes)/sizeof(*start_sizes); ++s) {
-    void* p = malloc(start_sizes[s]);
-    ASSERT_TRUE(p);
-    // The larger the start-size, the larger the non-reallocing delta.
-    for (int d = 0; d < s*2; ++d) {
-      void* new_p = realloc(p, start_sizes[s] + deltas[d]);
-      ASSERT_EQ(p, new_p);  // realloc should not allocate new memory
-    }
-    // Test again, but this time reallocing smaller first.
-    for (int d = 0; d < s*2; ++d) {
-      void* new_p = realloc(p, start_sizes[s] - deltas[d]);
-      ASSERT_EQ(p, new_p);  // realloc should not allocate new memory
-    }
-    free(p);
-  }
-}
-
-TEST(Allocators, Realloc2) {
-  for (int src_size = 0; src_size >= 0; src_size = NextSize(src_size)) {
-    for (int dst_size = 0; dst_size >= 0; dst_size = NextSize(dst_size)) {
-      unsigned char* src = reinterpret_cast<unsigned char*>(malloc(src_size));
-      Fill(src, src_size);
-      unsigned char* dst =
-          reinterpret_cast<unsigned char*>(realloc(src, dst_size));
-      EXPECT_TRUE(Valid(dst, min(src_size, dst_size)));
-      Fill(dst, dst_size);
-      EXPECT_TRUE(Valid(dst, dst_size));
-      if (dst != NULL) free(dst);
-    }
-  }
-
-  // Now make sure realloc works correctly even when we overflow the
-  // packed cache, so some entries are evicted from the cache.
-  // The cache has 2^12 entries, keyed by page number.
-  const int kNumEntries = 1 << 14;
-  int** p = reinterpret_cast<int**>(malloc(sizeof(*p) * kNumEntries));
-  int sum = 0;
-  for (int i = 0; i < kNumEntries; i++) {
-    // no page size is likely to be bigger than 8192?
-    p[i] = reinterpret_cast<int*>(malloc(8192));
-    p[i][1000] = i;              // use memory deep in the heart of p
-  }
-  for (int i = 0; i < kNumEntries; i++) {
-    p[i] = reinterpret_cast<int*>(realloc(p[i], 9000));
-  }
-  for (int i = 0; i < kNumEntries; i++) {
-    sum += p[i][1000];
-    free(p[i]);
-  }
-  EXPECT_EQ(kNumEntries/2 * (kNumEntries - 1), sum);  // assume kNE is even
-  free(p);
-}
-
-// Test recalloc
-TEST(Allocators, Recalloc) {
-  for (int src_size = 0; src_size >= 0; src_size = NextSize(src_size)) {
-    for (int dst_size = 0; dst_size >= 0; dst_size = NextSize(dst_size)) {
-      unsigned char* src =
-          reinterpret_cast<unsigned char*>(_recalloc(NULL, 1, src_size));
-      EXPECT_TRUE(IsZeroed(src, src_size));
-      Fill(src, src_size);
-      unsigned char* dst =
-          reinterpret_cast<unsigned char*>(_recalloc(src, 1, dst_size));
-      EXPECT_TRUE(Valid(dst, min(src_size, dst_size)));
-      Fill(dst, dst_size);
-      EXPECT_TRUE(Valid(dst, dst_size));
-      if (dst != NULL)
-        free(dst);
-    }
-  }
-}
-
-// Test windows specific _aligned_malloc() and _aligned_free() methods.
-TEST(Allocators, AlignedMalloc) {
-  // Try allocating data with a bunch of alignments and sizes
-  static const int kTestAlignments[] = {8, 16, 256, 4096, 8192, 16384};
-  for (int size = 1; size > 0; size = NextSize(size)) {
-    for (int i = 0; i < arraysize(kTestAlignments); ++i) {
-      unsigned char* ptr = static_cast<unsigned char*>(
-          _aligned_malloc(size, kTestAlignments[i]));
-      CheckAlignment(ptr, kTestAlignments[i]);
-      Fill(ptr, size);
-      EXPECT_TRUE(Valid(ptr, size));
-
-      // Make a second allocation of the same size and alignment to prevent
-      // allocators from passing this test by accident.  Per jar, tcmalloc
-      // provides allocations for new (never before seen) sizes out of a thread
-      // local heap of a given "size class."  Each time the test requests a new
-      // size, it will usually get the first element of a span, which is a
-      // 4K aligned allocation.
-      unsigned char* ptr2 = static_cast<unsigned char*>(
-          _aligned_malloc(size, kTestAlignments[i]));
-      CheckAlignment(ptr2, kTestAlignments[i]);
-      Fill(ptr2, size);
-      EXPECT_TRUE(Valid(ptr2, size));
-
-      // Should never happen, but sanity check just in case.
-      ASSERT_NE(ptr, ptr2);
-      _aligned_free(ptr);
-      _aligned_free(ptr2);
-    }
-  }
-}
-
-int main(int argc, char** argv) {
-  testing::InitGoogleTest(&argc, argv);
-  return RUN_ALL_TESTS();
-}
diff --git a/base/allocator/tcmalloc_unittest.cc b/base/allocator/tcmalloc_unittest.cc
index 0f7082eb..04a1466 100644
--- a/base/allocator/tcmalloc_unittest.cc
+++ b/base/allocator/tcmalloc_unittest.cc
@@ -1,96 +1,222 @@
 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
+
 #include <stddef.h>
 #include <stdio.h>
 
+#include "base/logging.h"
+#include "base/process/process_metrics.h"
+#include "build/build_config.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-// TCMalloc header files.
-#include "common.h"  // For TCMalloc constants like page size, etc.
-
-// TCMalloc implementation.
-#include "debugallocation_shim.cc"
+#if defined(USE_TCMALLOC)
+extern "C" {
+void* tc_malloc(size_t size);
+void tc_free(void*);
+}
 
 namespace {
 
+using std::min;
+
+#ifdef NDEBUG
 void* TCMallocDoMallocForTest(size_t size) {
-  return do_malloc(size);
+  return tc_malloc(size);
 }
 
 void TCMallocDoFreeForTest(void* ptr) {
-  do_free(ptr);
+  tc_free(ptr);
+}
+#endif
+
+// Fill a buffer of the specified size with a predetermined pattern
+static void Fill(unsigned char* buffer, int n) {
+  for (int i = 0; i < n; i++) {
+    buffer[i] = (i & 0xff);
+  }
 }
 
-size_t ExcludeSpaceForMarkForTest(size_t size) {
-  return ExcludeSpaceForMark(size);
+// Check that the specified buffer has the predetermined pattern
+// generated by Fill()
+static bool Valid(unsigned char* buffer, int n) {
+  for (int i = 0; i < n; i++) {
+    if (buffer[i] != (i & 0xff)) {
+      return false;
+    }
+  }
+  return true;
+}
+
+// Return the next interesting size/delta to check.  Returns -1 if no more.
+static int NextSize(int size) {
+  if (size < 100)
+    return size + 1;
+
+  if (size < 100000) {
+    // Find next power of two
+    int power = 1;
+    while (power < size)
+      power <<= 1;
+
+    // Yield (power-1, power, power+1)
+    if (size < power - 1)
+      return power - 1;
+
+    if (size == power - 1)
+      return power;
+
+    CHECK_EQ(size, power);
+    return power + 1;
+  } else {
+    return -1;
+  }
+}
+
+static void TestCalloc(size_t n, size_t s, bool ok) {
+  char* p = reinterpret_cast<char*>(calloc(n, s));
+  if (!ok) {
+    EXPECT_EQ(NULL, p) << "calloc(n, s) should not succeed";
+  } else {
+    EXPECT_NE(reinterpret_cast<void*>(NULL), p)
+        << "calloc(n, s) should succeed";
+    for (size_t i = 0; i < n * s; i++) {
+      EXPECT_EQ('\0', p[i]);
+    }
+    free(p);
+  }
 }
 
 }  // namespace
 
-TEST(TCMallocFreeCheck, BadPointerInFirstPageOfTheLargeObject) {
-  char* p = reinterpret_cast<char*>(
-      TCMallocDoMallocForTest(ExcludeSpaceForMarkForTest(kMaxSize + 1)));
-  for (int offset = 1; offset < kPageSize ; offset <<= 1) {
+TEST(TCMallocTest, Malloc) {
+  // Try allocating data with a bunch of alignments and sizes
+  for (int size = 1; size < 1048576; size *= 2) {
+    unsigned char* ptr = reinterpret_cast<unsigned char*>(malloc(size));
+    // Should be 2 byte aligned
+    EXPECT_EQ(0u, reinterpret_cast<uintptr_t>(ptr) & 1);
+    Fill(ptr, size);
+    EXPECT_TRUE(Valid(ptr, size));
+    free(ptr);
+  }
+}
+
+TEST(TCMallocTest, Calloc) {
+  TestCalloc(0, 0, true);
+  TestCalloc(0, 1, true);
+  TestCalloc(1, 1, true);
+  TestCalloc(1 << 10, 0, true);
+  TestCalloc(1 << 20, 0, true);
+  TestCalloc(0, 1 << 10, true);
+  TestCalloc(0, 1 << 20, true);
+  TestCalloc(1 << 20, 2, true);
+  TestCalloc(2, 1 << 20, true);
+  TestCalloc(1000, 1000, true);
+}
+
+#ifdef NDEBUG
+// This makes sure that reallocing a small number of bytes in either
+// direction doesn't cause us to allocate new memory. Tcmalloc in debug mode
+// does not follow this.
+TEST(TCMallocTest, ReallocSmallDelta) {
+  int start_sizes[] = {100, 1000, 10000, 100000};
+  int deltas[] = {1, -2, 4, -8, 16, -32, 64, -128};
+
+  for (unsigned s = 0; s < sizeof(start_sizes) / sizeof(*start_sizes); ++s) {
+    void* p = malloc(start_sizes[s]);
+    ASSERT_TRUE(p);
+    // The larger the start-size, the larger the non-reallocing delta.
+    for (unsigned d = 0; d < s * 2; ++d) {
+      void* new_p = realloc(p, start_sizes[s] + deltas[d]);
+      ASSERT_EQ(p, new_p);  // realloc should not allocate new memory
+    }
+    // Test again, but this time reallocing smaller first.
+    for (unsigned d = 0; d < s * 2; ++d) {
+      void* new_p = realloc(p, start_sizes[s] - deltas[d]);
+      ASSERT_EQ(p, new_p);  // realloc should not allocate new memory
+    }
+    free(p);
+  }
+}
+#endif
+
+TEST(TCMallocTest, Realloc) {
+  for (int src_size = 0; src_size >= 0; src_size = NextSize(src_size)) {
+    for (int dst_size = 0; dst_size >= 0; dst_size = NextSize(dst_size)) {
+      unsigned char* src = reinterpret_cast<unsigned char*>(malloc(src_size));
+      Fill(src, src_size);
+      unsigned char* dst =
+          reinterpret_cast<unsigned char*>(realloc(src, dst_size));
+      EXPECT_TRUE(Valid(dst, min(src_size, dst_size)));
+      Fill(dst, dst_size);
+      EXPECT_TRUE(Valid(dst, dst_size));
+      if (dst != NULL)
+        free(dst);
+    }
+  }
+
+  // Now make sure realloc works correctly even when we overflow the
+  // packed cache, so some entries are evicted from the cache.
+  // The cache has 2^12 entries, keyed by page number.
+  const int kNumEntries = 1 << 14;
+  int** p = reinterpret_cast<int**>(malloc(sizeof(*p) * kNumEntries));
+  int sum = 0;
+  for (int i = 0; i < kNumEntries; i++) {
+    // no page size is likely to be bigger than 8192?
+    p[i] = reinterpret_cast<int*>(malloc(8192));
+    p[i][1000] = i;  // use memory deep in the heart of p
+  }
+  for (int i = 0; i < kNumEntries; i++) {
+    p[i] = reinterpret_cast<int*>(realloc(p[i], 9000));
+  }
+  for (int i = 0; i < kNumEntries; i++) {
+    sum += p[i][1000];
+    free(p[i]);
+  }
+  EXPECT_EQ(kNumEntries / 2 * (kNumEntries - 1), sum);  // assume kNE is even
+  free(p);
+}
+
+#ifdef NDEBUG
+TEST(TCMallocFreeTest, BadPointerInFirstPageOfTheLargeObject) {
+  const size_t kPageSize = base::GetPageSize();
+  char* p =
+      reinterpret_cast<char*>(TCMallocDoMallocForTest(10 * kPageSize + 1));
+  for (unsigned offset = 1; offset < kPageSize; offset <<= 1) {
     ASSERT_DEATH(TCMallocDoFreeForTest(p + offset),
                  "Pointer is not pointing to the start of a span");
   }
 }
 
-TEST(TCMallocFreeCheck, BadPageAlignedPointerInsideLargeObject) {
-  char* p = reinterpret_cast<char*>(
-      TCMallocDoMallocForTest(ExcludeSpaceForMarkForTest(kMaxSize + 1)));
+TEST(TCMallocFreeTest, BadPageAlignedPointerInsideLargeObject) {
+  const size_t kPageSize = base::GetPageSize();
+  const size_t kMaxSize = 10 * kPageSize;
+  char* p = reinterpret_cast<char*>(TCMallocDoMallocForTest(kMaxSize + 1));
 
-  for (int offset = kPageSize; offset < kMaxSize; offset += kPageSize) {
+  for (unsigned offset = kPageSize; offset < kMaxSize; offset += kPageSize) {
     // Only the first and last page of a span are in heap map. So for others
     // tcmalloc will give a general error of invalid pointer.
-    ASSERT_DEATH(TCMallocDoFreeForTest(p + offset),
-                 "Attempt to free invalid pointer");
+    ASSERT_DEATH(TCMallocDoFreeForTest(p + offset), "");
   }
   ASSERT_DEATH(TCMallocDoFreeForTest(p + kMaxSize),
                "Pointer is not pointing to the start of a span");
 }
 
-TEST(TCMallocFreeCheck, DoubleFreeLargeObject) {
-  char* p = reinterpret_cast<char*>(
-      TCMallocDoMallocForTest(ExcludeSpaceForMarkForTest(kMaxSize + 1)));
+TEST(TCMallocFreeTest, DoubleFreeLargeObject) {
+  const size_t kMaxSize = 10 * base::GetPageSize();
+  char* p = reinterpret_cast<char*>(TCMallocDoMallocForTest(kMaxSize + 1));
   ASSERT_DEATH(TCMallocDoFreeForTest(p); TCMallocDoFreeForTest(p),
                "Object was not in-use");
 }
 
-
-#ifdef NDEBUG
-TEST(TCMallocFreeCheck, DoubleFreeSmallObject) {
-  for (size_t size = 1;
-       size <= ExcludeSpaceForMarkForTest(kMaxSize);
-       size <<= 1) {
+TEST(TCMallocFreeTest, DoubleFreeSmallObject) {
+  const size_t kPageSize = base::GetPageSize();
+  for (size_t size = 1; size <= kPageSize; size <<= 1) {
     char* p = reinterpret_cast<char*>(TCMallocDoMallocForTest(size));
     ASSERT_DEATH(TCMallocDoFreeForTest(p); TCMallocDoFreeForTest(p),
                  "Circular loop in list detected");
   }
 }
-#else
-TEST(TCMallocFreeCheck, DoubleFreeSmallObject) {
-  size_t size = 1;
+#endif  // NDEBUG
 
-  // When the object is small, tcmalloc validation can not distinguish normal
-  // memory corruption or double free, because there's not enough space in
-  // freed objects to keep the mark.
-  for (; size <= ExcludeSpaceForMarkForTest(kMinClassSize); size <<= 1) {
-    char* p = reinterpret_cast<char*>(TCMallocDoMallocForTest(size));
-    ASSERT_DEATH(TCMallocDoFreeForTest(p); TCMallocDoFreeForTest(p),
-                 "Memory corrupted");
-  }
-
-  for (; size <= ExcludeSpaceForMarkForTest(kMaxSize); size <<= 1) {
-    char* p = reinterpret_cast<char*>(TCMallocDoMallocForTest(size));
-    ASSERT_DEATH(TCMallocDoFreeForTest(p); TCMallocDoFreeForTest(p),
-                 "Attempt to double free");
-  }
-}
 #endif
-
-int main(int argc, char **argv) {
-  testing::InitGoogleTest(&argc, argv);
-  return RUN_ALL_TESTS();
-}
diff --git a/base/base.gyp b/base/base.gyp
index 6ab4b36..e067154bd 100644
--- a/base/base.gyp
+++ b/base/base.gyp
@@ -21,6 +21,7 @@
         'optimize': 'max',
       },
       'dependencies': [
+        'base_debugging_flags',
         'base_static',
         'allocator/allocator.gyp:allocator_extension_thunks',
         '../testing/gtest.gyp:gtest_prod',
@@ -426,6 +427,7 @@
       'target_name': 'base_unittests',
       'type': '<(gtest_target_type)',
       'sources': [
+        'allocator/tcmalloc_unittest.cc',
         'android/application_status_listener_unittest.cc',
         'android/content_uri_utils_unittest.cc',
         'android/jni_android_unittest.cc',
@@ -1076,6 +1078,18 @@
         }],
       ],
     },
+    {
+      # GN version: //base/debug:debugging_flags
+      'target_name': 'base_debugging_flags',
+      'toolsets': ['host', 'target'],
+      'includes': [ '../build/buildflag_header.gypi' ],
+      'variables': {
+        'buildflag_header_path': 'base/debug/debugging_flags.h',
+        'buildflag_flags': [
+          'ENABLE_PROFILING=<(profiling)',
+        ],
+      },
+    },
   ],
   'conditions': [
     ['OS=="ios" and "<(GENERATOR)"=="ninja"', {
@@ -1131,6 +1145,7 @@
             'base_target': 1,
           },
           'dependencies': [
+            'base_debugging_flags',
             'base_static_win64',
             'allocator/allocator.gyp:allocator_extension_thunks_win64',
             '../third_party/modp_b64/modp_b64.gyp:modp_b64_win64',
diff --git a/base/base.gypi b/base/base.gypi
index 35bd747..3ad9ccf 100644
--- a/base/base.gypi
+++ b/base/base.gypi
@@ -1018,6 +1018,8 @@
         ],
         'sources': [
           'i18n/base_i18n_export.h',
+          'i18n/base_i18n_switches.cc',
+          'i18n/base_i18n_switches.h',
           'i18n/bidi_line_iterator.cc',
           'i18n/bidi_line_iterator.h',
           'i18n/break_iterator.cc',
diff --git a/base/base_nacl.gyp b/base/base_nacl.gyp
index b2b4b7f..7010256 100644
--- a/base/base_nacl.gyp
+++ b/base/base_nacl.gyp
@@ -39,6 +39,9 @@
               '-fno-strict-aliasing',
             ],
           },
+          'dependencies': [
+            'base.gyp:base_debugging_flags',
+          ],
         },
         {
           'target_name': 'base_i18n_nacl',
@@ -115,6 +118,7 @@
           ],
           'dependencies': [
             '../third_party/libevent/libevent_nacl_nonsfi.gyp:event_nacl_nonsfi',
+            'base.gyp:base_debugging_flags',
           ],
         },
         {
diff --git a/base/basictypes.h b/base/basictypes.h
index c17cfbb..e39e29fb 100644
--- a/base/basictypes.h
+++ b/base/basictypes.h
@@ -26,7 +26,6 @@
 // DEPRECATED: Use std::numeric_limits (from <limits>) or
 // (U)INT{8,16,32,64}_{MIN,MAX} in case of globals (and include <stdint.h>).
 // http://crbug.com/138542
-const uint32 kuint32max =  0xFFFFFFFF;
 const uint64 kuint64max =  0xFFFFFFFFFFFFFFFFULL;
 const  int32 kint32max  =  0x7FFFFFFF;
 const  int64 kint64max  =  0x7FFFFFFFFFFFFFFFLL;
diff --git a/base/debug/BUILD.gn b/base/debug/BUILD.gn
index be8084e..ec9298a7 100644
--- a/base/debug/BUILD.gn
+++ b/base/debug/BUILD.gn
@@ -2,6 +2,9 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import("//build/buildflag_header.gni")
+import("//build/config/compiler/compiler.gni")
+
 source_set("debug") {
   sources = [
     "alias.cc",
@@ -58,6 +61,7 @@
   configs += [ "//base:base_implementation" ]
 
   deps = [
+    ":debugging_flags",
     "//base:base_static",
     "//base/memory",
     "//base/process",
@@ -75,3 +79,9 @@
 
   visibility = [ "//base/*" ]
 }
+
+buildflag_header("debugging_flags") {
+  header = "debugging_flags.h"
+
+  flags = [ "ENABLE_PROFILING=$enable_profiling" ]
+}
diff --git a/base/debug/profiler.cc b/base/debug/profiler.cc
index 924c769..b499c14 100644
--- a/base/debug/profiler.cc
+++ b/base/debug/profiler.cc
@@ -6,6 +6,7 @@
 
 #include <string>
 
+#include "base/debug/debugging_flags.h"
 #include "base/process/process_handle.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
@@ -15,7 +16,7 @@
 #endif  // defined(OS_WIN)
 
 // TODO(peria): Enable profiling on Windows.
-#if defined(ENABLE_PROFILING) && !defined(NO_TCMALLOC) && !defined(OS_WIN)
+#if BUILDFLAG(ENABLE_PROFILING) && !defined(NO_TCMALLOC) && !defined(OS_WIN)
 #include "third_party/tcmalloc/chromium/src/gperftools/profiler.h"
 #endif
 
@@ -23,7 +24,7 @@
 namespace debug {
 
 // TODO(peria): Enable profiling on Windows.
-#if defined(ENABLE_PROFILING) && !defined(NO_TCMALLOC) && !defined(OS_WIN)
+#if BUILDFLAG(ENABLE_PROFILING) && !defined(NO_TCMALLOC) && !defined(OS_WIN)
 
 static int profile_count = 0;
 
diff --git a/base/i18n/base_i18n_switches.cc b/base/i18n/base_i18n_switches.cc
new file mode 100644
index 0000000..44e8393
--- /dev/null
+++ b/base/i18n/base_i18n_switches.cc
@@ -0,0 +1,16 @@
+// 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.
+
+#include "base/i18n/base_i18n_switches.h"
+
+namespace switches {
+
+// Force the UI to a specific direction. Valid values are "ltr" (left-to-right)
+// and "rtl" (right-to-left).
+const char kForceUIDirection[]              = "force-ui-direction";
+
+const char kForceUIDirectionLTR[]           = "ltr";
+const char kForceUIDirectionRTL[]           = "rtl";
+
+}  // namespace switches
diff --git a/base/i18n/base_i18n_switches.h b/base/i18n/base_i18n_switches.h
new file mode 100644
index 0000000..f00cff3
--- /dev/null
+++ b/base/i18n/base_i18n_switches.h
@@ -0,0 +1,20 @@
+// 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.
+
+#ifndef BASE_I18N_BASE_I18N_SWITCHES_H_
+#define BASE_I18N_BASE_I18N_SWITCHES_H_
+
+#include "base/i18n/base_i18n_export.h"
+
+namespace switches {
+
+BASE_I18N_EXPORT extern const char kForceUIDirection[];
+
+// kForceUIDirection choices.
+BASE_I18N_EXPORT extern const char kForceUIDirectionLTR[];
+BASE_I18N_EXPORT extern const char kForceUIDirectionRTL[];
+
+}  // namespace switches
+
+#endif  // BASE_I18N_BASE_I18N_SWITCHES_H_
diff --git a/base/i18n/rtl.cc b/base/i18n/rtl.cc
index ac9589c..adcf6deb0 100644
--- a/base/i18n/rtl.cc
+++ b/base/i18n/rtl.cc
@@ -6,7 +6,9 @@
 
 #include <algorithm>
 
+#include "base/command_line.h"
 #include "base/files/file_path.h"
+#include "base/i18n/base_i18n_switches.h"
 #include "base/logging.h"
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
@@ -64,6 +66,30 @@
   return base::i18n::UNKNOWN_DIRECTION;
 }
 
+// Gets the explicitly forced text direction for debugging. If no forcing is
+// applied, returns UNKNOWN_DIRECTION.
+base::i18n::TextDirection GetForcedTextDirection() {
+  // On iOS, check for RTL forcing.
+#if defined(OS_IOS)
+  if (base::ios::IsInForcedRTL())
+    return base::i18n::RIGHT_TO_LEFT;
+#endif
+
+  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+  if (command_line->HasSwitch(switches::kForceUIDirection)) {
+    std::string force_flag =
+        command_line->GetSwitchValueASCII(switches::kForceUIDirection);
+
+    if (force_flag == switches::kForceUIDirectionLTR)
+      return base::i18n::LEFT_TO_RIGHT;
+
+    if (force_flag == switches::kForceUIDirectionRTL)
+      return base::i18n::RIGHT_TO_LEFT;
+  }
+
+  return base::i18n::UNKNOWN_DIRECTION;
+}
+
 }  // namespace
 
 namespace base {
@@ -135,11 +161,10 @@
 }
 
 TextDirection GetTextDirectionForLocaleInStartUp(const char* locale_name) {
-// On iOS, check for RTL forcing.
-#if defined(OS_IOS)
-  if (ios::IsInForcedRTL())
-    return RIGHT_TO_LEFT;
-#endif
+  // Check for direction forcing.
+  TextDirection forced_direction = GetForcedTextDirection();
+  if (forced_direction != UNKNOWN_DIRECTION)
+    return forced_direction;
 
   // This list needs to be updated in alphabetical order if we add more RTL
   // locales.
@@ -155,11 +180,10 @@
 }
 
 TextDirection GetTextDirectionForLocale(const char* locale_name) {
-  // On iOS, check for RTL forcing.
-#if defined(OS_IOS)
-  if (ios::IsInForcedRTL())
-    return RIGHT_TO_LEFT;
-#endif
+  // Check for direction forcing.
+  TextDirection forced_direction = GetForcedTextDirection();
+  if (forced_direction != UNKNOWN_DIRECTION)
+    return forced_direction;
 
   UErrorCode status = U_ZERO_ERROR;
   ULayoutType layout_dir = uloc_getCharacterOrientation(locale_name, &status);
diff --git a/base/macros.h b/base/macros.h
index 4adbbb07..5f8d9705d2d 100644
--- a/base/macros.h
+++ b/base/macros.h
@@ -27,13 +27,6 @@
   TypeName(const TypeName&);               \
   void operator=(const TypeName&)
 
-// An older, deprecated, politically incorrect name for the above.
-// NOTE: The usage of this macro was banned from our code base, but some
-// third_party libraries are yet using it.
-// TODO(tfarina): Figure out how to fix the usage of this macro in the
-// third_party libraries and get rid of it.
-#define DISALLOW_EVIL_CONSTRUCTORS(TypeName) DISALLOW_COPY_AND_ASSIGN(TypeName)
-
 // A macro to disallow all the implicit constructors, namely the
 // default constructor, copy constructor and operator= functions.
 //
diff --git a/base/memory/discardable_shared_memory.cc b/base/memory/discardable_shared_memory.cc
index 2b0cfd0..24bd3e3 100644
--- a/base/memory/discardable_shared_memory.cc
+++ b/base/memory/discardable_shared_memory.cc
@@ -122,15 +122,8 @@
   if (!checked_size.IsValid())
     return false;
 
-#if defined(OS_MACOSX) && !defined(OS_IOS)
-  // DiscardableSharedMemory does not yet support a Mach-implementation, so
-  // force the underlying primitive to be a POSIX fd. https://crbug.com/547239.
-  if (!shared_memory_.CreateAndMapAnonymousPosix(checked_size.ValueOrDie()))
-    return false;
-#else
   if (!shared_memory_.CreateAndMapAnonymous(checked_size.ValueOrDie()))
     return false;
-#endif  // defined(OS_MACOSX) && !defined(OS_IOS)
 
   mapped_size_ =
       shared_memory_.mapped_size() - AlignToPageSize(sizeof(SharedState));
diff --git a/base/memory/ref_counted.h b/base/memory/ref_counted.h
index 26c6551..85dd433 100644
--- a/base/memory/ref_counted.h
+++ b/base/memory/ref_counted.h
@@ -14,7 +14,6 @@
 #ifndef NDEBUG
 #include "base/logging.h"
 #endif
-#include "base/move.h"
 #include "base/threading/thread_collision_warner.h"
 #include "build/build_config.h"
 
@@ -265,7 +264,6 @@
 //
 template <class T>
 class scoped_refptr {
-  TYPE_WITH_MOVE_CONSTRUCTOR_FOR_CPP_03(scoped_refptr)
  public:
   typedef T element_type;
 
@@ -277,17 +275,24 @@
       AddRef(ptr_);
   }
 
+  // Copy constructor.
   scoped_refptr(const scoped_refptr<T>& r) : ptr_(r.ptr_) {
     if (ptr_)
       AddRef(ptr_);
   }
 
+  // Copy conversion constructor.
   template <typename U>
   scoped_refptr(const scoped_refptr<U>& r) : ptr_(r.get()) {
     if (ptr_)
       AddRef(ptr_);
   }
 
+  // Move constructor. This is required in addition to the conversion
+  // constructor below in order for clang to warn about pessimizing moves.
+  scoped_refptr(scoped_refptr&& r) : ptr_(r.get()) { r.ptr_ = nullptr; }
+
+  // Move conversion constructor.
   template <typename U>
   scoped_refptr(scoped_refptr<U>&& r) : ptr_(r.get()) {
     r.ptr_ = nullptr;
diff --git a/base/move.h b/base/move.h
index fe0517e..6743eb7 100644
--- a/base/move.h
+++ b/base/move.h
@@ -63,9 +63,4 @@
                                                                 \
  private:
 
-#define TYPE_WITH_MOVE_CONSTRUCTOR_FOR_CPP_03(type) \
- public: \
-  type&& Pass() WARN_UNUSED_RESULT { return std::move(*this); } \
- private:
-
 #endif  // BASE_MOVE_H_
diff --git a/base/path_service.cc b/base/path_service.cc
index 97a0ce5..3b9b69e1 100644
--- a/base/path_service.cc
+++ b/base/path_service.cc
@@ -126,19 +126,9 @@
     providers = &base_provider_posix;
 #endif
   }
-
-  ~PathData() {
-    Provider* p = providers;
-    while (p) {
-      Provider* next = p->next;
-      if (!p->is_static)
-        delete p;
-      p = next;
-    }
-  }
 };
 
-static LazyInstance<PathData> g_path_data = LAZY_INSTANCE_INITIALIZER;
+static LazyInstance<PathData>::Leaky g_path_data = LAZY_INSTANCE_INITIALIZER;
 
 static PathData* GetPathData() {
   return g_path_data.Pointer();
diff --git a/base/pickle.cc b/base/pickle.cc
index 489c7f8..6fcdece3 100644
--- a/base/pickle.cc
+++ b/base/pickle.cc
@@ -30,7 +30,7 @@
   const char* read_from = GetReadPointerAndAdvance<Type>();
   if (!read_from)
     return false;
-  if (sizeof(Type) > sizeof(uint32))
+  if (sizeof(Type) > sizeof(uint32_t))
     memcpy(result, read_from, sizeof(*result));
   else
     *result = *reinterpret_cast<const Type*>(read_from);
@@ -72,9 +72,9 @@
     int num_elements,
     size_t size_element) {
   // Check for int32 overflow.
-  int64 num_bytes = static_cast<int64>(num_elements) * size_element;
+  int64_t num_bytes = static_cast<int64_t>(num_elements) * size_element;
   int num_bytes32 = static_cast<int>(num_bytes);
-  if (num_bytes != static_cast<int64>(num_bytes32))
+  if (num_bytes != static_cast<int64_t>(num_bytes32))
     return NULL;
   return GetReadPointerAndAdvance(num_bytes32);
 }
@@ -91,26 +91,26 @@
   return ReadBuiltinType(result);
 }
 
-bool PickleIterator::ReadUInt16(uint16* result) {
+bool PickleIterator::ReadUInt16(uint16_t* result) {
   return ReadBuiltinType(result);
 }
 
-bool PickleIterator::ReadUInt32(uint32* result) {
+bool PickleIterator::ReadUInt32(uint32_t* result) {
   return ReadBuiltinType(result);
 }
 
-bool PickleIterator::ReadInt64(int64* result) {
+bool PickleIterator::ReadInt64(int64_t* result) {
   return ReadBuiltinType(result);
 }
 
-bool PickleIterator::ReadUInt64(uint64* result) {
+bool PickleIterator::ReadUInt64(uint64_t* result) {
   return ReadBuiltinType(result);
 }
 
 bool PickleIterator::ReadSizeT(size_t* result) {
   // Always read size_t as a 64-bit value to ensure compatibility between 32-bit
   // and 64-bit processes.
-  uint64 result_uint64 = 0;
+  uint64_t result_uint64 = 0;
   bool success = ReadBuiltinType(&result_uint64);
   *result = static_cast<size_t>(result_uint64);
   // Fail if the cast above truncates the value.
@@ -207,7 +207,7 @@
   return true;
 }
 
-// Payload is uint32 aligned.
+// Payload is uint32_t aligned.
 
 Pickle::Pickle()
     : header_(NULL),
@@ -222,7 +222,7 @@
 
 Pickle::Pickle(int header_size)
     : header_(NULL),
-      header_size_(bits::Align(header_size, sizeof(uint32))),
+      header_size_(bits::Align(header_size, sizeof(uint32_t))),
       capacity_after_header_(0),
       write_offset_(0) {
   DCHECK_GE(static_cast<size_t>(header_size), sizeof(Header));
@@ -242,7 +242,7 @@
   if (header_size_ > static_cast<unsigned int>(data_len))
     header_size_ = 0;
 
-  if (header_size_ != bits::Align(header_size_, sizeof(uint32)))
+  if (header_size_ != bits::Align(header_size_, sizeof(uint32_t)))
     header_size_ = 0;
 
   // If there is anything wrong with the data, we're not going to use it.
@@ -310,12 +310,12 @@
 }
 
 void Pickle::Reserve(size_t length) {
-  size_t data_len = bits::Align(length, sizeof(uint32));
+  size_t data_len = bits::Align(length, sizeof(uint32_t));
   DCHECK_GE(data_len, length);
 #ifdef ARCH_CPU_64_BITS
-  DCHECK_LE(data_len, kuint32max);
+  DCHECK_LE(data_len, std::numeric_limits<uint32_t>::max());
 #endif
-  DCHECK_LE(write_offset_, kuint32max - data_len);
+  DCHECK_LE(write_offset_, std::numeric_limits<uint32_t>::max() - data_len);
   size_t new_size = write_offset_ + data_len;
   if (new_size > capacity_after_header_)
     Resize(capacity_after_header_ * 2 + new_size);
@@ -354,7 +354,7 @@
                       const char* start,
                       const char* end,
                       size_t* pickle_size) {
-  DCHECK_EQ(header_size, bits::Align(header_size, sizeof(uint32)));
+  DCHECK_EQ(header_size, bits::Align(header_size, sizeof(uint32_t)));
   DCHECK_GE(header_size, sizeof(Header));
   DCHECK_LE(header_size, static_cast<size_t>(kPayloadUnit));
 
@@ -388,12 +388,12 @@
   DCHECK_NE(kCapacityReadOnly, capacity_after_header_)
       << "oops: pickle is readonly";
   MSAN_CHECK_MEM_IS_INITIALIZED(data, length);
-  size_t data_len = bits::Align(length, sizeof(uint32));
+  size_t data_len = bits::Align(length, sizeof(uint32_t));
   DCHECK_GE(data_len, length);
 #ifdef ARCH_CPU_64_BITS
-  DCHECK_LE(data_len, kuint32max);
+  DCHECK_LE(data_len, std::numeric_limits<uint32_t>::max());
 #endif
-  DCHECK_LE(write_offset_, kuint32max - data_len);
+  DCHECK_LE(write_offset_, std::numeric_limits<uint32_t>::max() - data_len);
   size_t new_size = write_offset_ + data_len;
   if (new_size > capacity_after_header_) {
     size_t new_capacity = capacity_after_header_ * 2;
@@ -406,7 +406,7 @@
   char* write = mutable_payload() + write_offset_;
   memcpy(write, data, length);
   memset(write + length, 0, data_len - length);
-  header_->payload_size = static_cast<uint32>(new_size);
+  header_->payload_size = static_cast<uint32_t>(new_size);
   write_offset_ = new_size;
 }
 
diff --git a/base/pickle.h b/base/pickle.h
index 22b8055..72b33ddc 100644
--- a/base/pickle.h
+++ b/base/pickle.h
@@ -5,10 +5,11 @@
 #ifndef BASE_PICKLE_H_
 #define BASE_PICKLE_H_
 
+#include <stdint.h>
+
 #include <string>
 
 #include "base/base_export.h"
-#include "base/basictypes.h"
 #include "base/compiler_specific.h"
 #include "base/gtest_prod_util.h"
 #include "base/logging.h"
@@ -34,10 +35,10 @@
   bool ReadBool(bool* result) WARN_UNUSED_RESULT;
   bool ReadInt(int* result) WARN_UNUSED_RESULT;
   bool ReadLong(long* result) WARN_UNUSED_RESULT;
-  bool ReadUInt16(uint16* result) WARN_UNUSED_RESULT;
-  bool ReadUInt32(uint32* result) WARN_UNUSED_RESULT;
-  bool ReadInt64(int64* result) WARN_UNUSED_RESULT;
-  bool ReadUInt64(uint64* result) WARN_UNUSED_RESULT;
+  bool ReadUInt16(uint16_t* result) WARN_UNUSED_RESULT;
+  bool ReadUInt32(uint32_t* result) WARN_UNUSED_RESULT;
+  bool ReadInt64(int64_t* result) WARN_UNUSED_RESULT;
+  bool ReadUInt64(uint64_t* result) WARN_UNUSED_RESULT;
   bool ReadSizeT(size_t* result) WARN_UNUSED_RESULT;
   bool ReadFloat(float* result) WARN_UNUSED_RESULT;
   bool ReadDouble(double* result) WARN_UNUSED_RESULT;
@@ -179,22 +180,14 @@
   bool WriteLongUsingDangerousNonPortableLessPersistableForm(long value) {
     return WritePOD(value);
   }
-  bool WriteUInt16(uint16 value) {
-    return WritePOD(value);
-  }
-  bool WriteUInt32(uint32 value) {
-    return WritePOD(value);
-  }
-  bool WriteInt64(int64 value) {
-    return WritePOD(value);
-  }
-  bool WriteUInt64(uint64 value) {
-    return WritePOD(value);
-  }
+  bool WriteUInt16(uint16_t value) { return WritePOD(value); }
+  bool WriteUInt32(uint32_t value) { return WritePOD(value); }
+  bool WriteInt64(int64_t value) { return WritePOD(value); }
+  bool WriteUInt64(uint64_t value) { return WritePOD(value); }
   bool WriteSizeT(size_t value) {
     // Always write size_t as a 64-bit value to ensure compatibility between
     // 32-bit and 64-bit processes.
-    return WritePOD(static_cast<uint64>(value));
+    return WritePOD(static_cast<uint64_t>(value));
   }
   bool WriteFloat(float value) {
     return WritePOD(value);
@@ -219,7 +212,7 @@
 
   // Payload follows after allocation of Header (header size is customizable).
   struct Header {
-    uint32 payload_size;  // Specifies the size of the payload.
+    uint32_t payload_size;  // Specifies the size of the payload.
   };
 
   // Returns the header, cast to a user-specified type T.  The type T must be a
diff --git a/base/profiler/native_stack_sampler_win.cc b/base/profiler/native_stack_sampler_win.cc
index 7b41fee..87bb6ce 100644
--- a/base/profiler/native_stack_sampler_win.cc
+++ b/base/profiler/native_stack_sampler_win.cc
@@ -138,21 +138,30 @@
 }
 
 // Walks the stack represented by |context| from the current frame downwards,
-// recording the instruction pointers for each frame in |instruction_pointers|.
-int RecordStack(CONTEXT* context, int max_stack_size,
-                const void* instruction_pointers[],
-                ScopedModuleHandle modules[]) {
+// recording the instruction pointers for each frame in |instruction_pointers|
+// and associated modules in |modules|.
+void RecordStack(CONTEXT* context,
+                 std::vector<const void*>* instruction_pointers,
+                 std::vector<ScopedModuleHandle>* modules) {
 #ifdef _WIN64
+  DCHECK(instruction_pointers->empty());
+  DCHECK(modules->empty());
+
+  // Reserve enough memory for most stacks, to avoid repeated
+  // allocations. Approximately 99.5% of recorded stacks are 64 frames or fewer.
+  instruction_pointers->reserve(64);
+  modules->reserve(64);
+
   Win32StackFrameUnwinder frame_unwinder;
-  int i = 0;
-  for (; (i < max_stack_size) && context->Rip; ++i) {
-    instruction_pointers[i] = reinterpret_cast<const void*>(context->Rip);
-    if (!frame_unwinder.TryUnwind(context, &modules[i]))
-      return i;
+  while (context->Rip) {
+    const void* instruction_pointer =
+        reinterpret_cast<const void*>(context->Rip);
+    ScopedModuleHandle module;
+    if (!frame_unwinder.TryUnwind(context, &module))
+      return;
+    instruction_pointers->push_back(instruction_pointer);
+    modules->push_back(std::move(module));
   }
-  return i;
-#else
-  return 0;
 #endif
 }
 
@@ -259,22 +268,24 @@
 }
 
 // Suspends the thread with |thread_handle|, copies its stack and resumes the
-// thread, then records the stack into |instruction_pointers|. Returns the size
-// of the stack.
+// thread, then records the stack into |instruction_pointers| and associated
+// modules into |modules|.
 //
 // IMPORTANT NOTE: No allocations from the default heap may occur in the
 // ScopedSuspendThread scope, including indirectly via use of DCHECK/CHECK or
 // other logging statements. Otherwise this code can deadlock on heap locks in
-// the default heap acquired by the target thread before it was suspended. This
-// is why we pass instruction pointers as preallocated arrays.
-int SuspendThreadAndRecordStack(HANDLE thread_handle,
-                                const void* base_address,
-                                void* stack_copy_buffer,
-                                size_t stack_copy_buffer_size,
-                                int max_stack_size,
-                                const void* instruction_pointers[],
-                                ScopedModuleHandle modules[],
-                                NativeStackSamplerTestDelegate* test_delegate) {
+// the default heap acquired by the target thread before it was suspended.
+void SuspendThreadAndRecordStack(
+    HANDLE thread_handle,
+    const void* base_address,
+    void* stack_copy_buffer,
+    size_t stack_copy_buffer_size,
+    std::vector<const void*>* instruction_pointers,
+    std::vector<ScopedModuleHandle>* modules,
+    NativeStackSamplerTestDelegate* test_delegate) {
+  DCHECK(instruction_pointers->empty());
+  DCHECK(modules->empty());
+
   CONTEXT thread_context = {0};
   thread_context.ContextFlags = CONTEXT_FULL;
   // The stack bounds are saved to uintptr_ts for use outside
@@ -287,10 +298,10 @@
     ScopedSuspendThread suspend_thread(thread_handle);
 
     if (!suspend_thread.was_successful())
-      return 0;
+      return;
 
     if (!::GetThreadContext(thread_handle, &thread_context))
-      return 0;
+      return;
 #if defined(_WIN64)
     bottom = thread_context.Rsp;
 #else
@@ -298,7 +309,7 @@
 #endif
 
     if ((top - bottom) > stack_copy_buffer_size)
-      return 0;
+      return;
 
     std::memcpy(stack_copy_buffer, reinterpret_cast<const void*>(bottom),
                 top - bottom);
@@ -309,8 +320,7 @@
 
   RewritePointersToStackMemory(top, bottom, &thread_context, stack_copy_buffer);
 
-  return RecordStack(&thread_context, max_stack_size, instruction_pointers,
-                     modules);
+  RecordStack(&thread_context, instruction_pointers, modules);
 }
 
 // NativeStackSamplerWin ------------------------------------------------------
@@ -351,9 +361,8 @@
 
   // Copies the stack information represented by |instruction_pointers| into
   // |sample| and |modules|.
-  void CopyToSample(const void* const instruction_pointers[],
-                    const ScopedModuleHandle module_handles[],
-                    int stack_depth,
+  void CopyToSample(const std::vector<const void*>& instruction_pointers,
+                    const std::vector<ScopedModuleHandle>& module_handles,
                     StackSamplingProfiler::Sample* sample,
                     std::vector<StackSamplingProfiler::Module>* modules);
 
@@ -404,20 +413,12 @@
   if (!stack_copy_buffer_)
     return;
 
-  const int max_stack_size = 64;
-  const void* instruction_pointers[max_stack_size] = {0};
-  ScopedModuleHandle modules[max_stack_size];
-
-  int stack_depth = SuspendThreadAndRecordStack(thread_handle_.Get(),
-                                                thread_stack_base_address_,
-                                                stack_copy_buffer_.get(),
-                                                kStackCopyBufferSize,
-                                                max_stack_size,
-                                                instruction_pointers,
-                                                modules,
-                                                test_delegate_);
-  CopyToSample(instruction_pointers, modules, stack_depth, sample,
-               current_modules_);
+  std::vector<const void*> instruction_pointers;
+  std::vector<ScopedModuleHandle> modules;
+  SuspendThreadAndRecordStack(thread_handle_.Get(), thread_stack_base_address_,
+                              stack_copy_buffer_.get(), kStackCopyBufferSize,
+                              &instruction_pointers, &modules, test_delegate_);
+  CopyToSample(instruction_pointers, modules, sample, current_modules_);
 }
 
 void NativeStackSamplerWin::ProfileRecordingStopped() {
@@ -465,15 +466,15 @@
 }
 
 void NativeStackSamplerWin::CopyToSample(
-    const void* const instruction_pointers[],
-    const ScopedModuleHandle module_handles[],
-    int stack_depth,
+    const std::vector<const void*>& instruction_pointers,
+    const std::vector<ScopedModuleHandle>& module_handles,
     StackSamplingProfiler::Sample* sample,
     std::vector<StackSamplingProfiler::Module>* modules) {
+  DCHECK_EQ(instruction_pointers.size(), module_handles.size());
   sample->clear();
-  sample->reserve(stack_depth);
+  sample->reserve(instruction_pointers.size());
 
-  for (int i = 0; i < stack_depth; ++i) {
+  for (size_t i = 0; i < instruction_pointers.size(); ++i) {
     sample->push_back(StackSamplingProfiler::Frame(
         reinterpret_cast<uintptr_t>(instruction_pointers[i]),
         GetModuleIndex(module_handles[i].Get(), modules)));
diff --git a/base/win/event_trace_provider.h b/base/win/event_trace_provider.h
index 7907347..a87cb9c1 100644
--- a/base/win/event_trace_provider.h
+++ b/base/win/event_trace_provider.h
@@ -10,9 +10,12 @@
 #include <windows.h>
 #include <wmistr.h>
 #include <evntrace.h>
+#include <stdint.h>
+
+#include <limits>
 
 #include "base/base_export.h"
-#include "base/basictypes.h"
+#include "base/macros.h"
 
 namespace base {
 namespace win {
@@ -66,7 +69,7 @@
 
   void SetField(int field, size_t size, const void *data) {
     // DCHECK(field < N);
-    if ((field < N) && (size <= kuint32max)) {
+    if ((field < N) && (size <= std::numeric_limits<uint32_t>::max())) {
       fields[field].DataPtr = reinterpret_cast<ULONG64>(data);
       fields[field].Length = static_cast<ULONG>(size);
     }
diff --git a/blimp/BUILD.gn b/blimp/BUILD.gn
index 7dc92b8..d29270cc 100644
--- a/blimp/BUILD.gn
+++ b/blimp/BUILD.gn
@@ -45,6 +45,7 @@
 test("blimp_unittests") {
   deps = [
     "//blimp/client:unit_tests",
+    "//blimp/common:unit_tests",
     "//blimp/net:unit_tests",
   ]
 
diff --git a/blimp/client/BUILD.gn b/blimp/client/BUILD.gn
index edde7b61..48f647b 100644
--- a/blimp/client/BUILD.gn
+++ b/blimp/client/BUILD.gn
@@ -57,6 +57,7 @@
     "//base",
     "//base/test:run_all_unittests",
     "//base/test:test_support",
+    "//blimp/common:blimp_common",
     "//blimp/common/proto",
     "//blimp/net:blimp_net",
     "//blimp/net:test_support",
diff --git a/blimp/client/compositor/render_widget_message_processor.cc b/blimp/client/compositor/render_widget_message_processor.cc
index 23ad1de..73699fc0 100644
--- a/blimp/client/compositor/render_widget_message_processor.cc
+++ b/blimp/client/compositor/render_widget_message_processor.cc
@@ -5,6 +5,7 @@
 #include "blimp/client/compositor/render_widget_message_processor.h"
 
 #include "base/numerics/safe_conversions.h"
+#include "blimp/common/create_blimp_message.h"
 #include "blimp/common/proto/blimp_message.pb.h"
 #include "blimp/common/proto/compositor.pb.h"
 #include "blimp/common/proto/input.pb.h"
@@ -48,10 +49,10 @@
 void RenderWidgetMessageProcessor::SendCompositorMessage(
     const int tab_id,
     const cc::proto::CompositorMessage& message) {
-  scoped_ptr<BlimpMessage> blimp_message(new BlimpMessage);
-  blimp_message->set_target_tab_id(tab_id);
+  CompositorMessage* compositor_message;
+  scoped_ptr<BlimpMessage> blimp_message =
+      CreateBlimpMessage(&compositor_message, tab_id);
 
-  CompositorMessage* compositor_message = blimp_message->mutable_compositor();
   uint32_t render_widget_id = GetRenderWidgetId(tab_id);
   DCHECK_LT(0U, render_widget_id);
   compositor_message->set_render_widget_id(render_widget_id);
diff --git a/blimp/client/compositor/render_widget_message_processor_unittest.cc b/blimp/client/compositor/render_widget_message_processor_unittest.cc
index b2aa921..384c7314 100644
--- a/blimp/client/compositor/render_widget_message_processor_unittest.cc
+++ b/blimp/client/compositor/render_widget_message_processor_unittest.cc
@@ -6,6 +6,7 @@
 
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
+#include "blimp/common/create_blimp_message.h"
 #include "blimp/common/proto/blimp_message.pb.h"
 #include "blimp/common/proto/compositor.pb.h"
 #include "blimp/common/proto/render_widget.pb.h"
@@ -50,11 +51,8 @@
 void SendRenderWidgetMessage(BlimpMessageProcessor* processor,
                              int tab_id,
                              uint32_t rw_id) {
-  scoped_ptr<BlimpMessage> message(new BlimpMessage);
-  message->set_type(BlimpMessage::RENDER_WIDGET);
-  message->set_target_tab_id(tab_id);
-
-  RenderWidgetMessage* details = message->mutable_render_widget();
+  RenderWidgetMessage* details;
+  scoped_ptr<BlimpMessage> message = CreateBlimpMessage(&details, tab_id);
   details->set_type(RenderWidgetMessage::INITIALIZE);
   details->set_render_widget_id(rw_id);
   processor->ProcessMessage(std::move(message),
@@ -64,11 +62,8 @@
 void SendCompositorMessage(BlimpMessageProcessor* processor,
                              int tab_id,
                              uint32_t rw_id) {
-  scoped_ptr<BlimpMessage> message(new BlimpMessage);
-  message->set_type(BlimpMessage::COMPOSITOR);
-  message->set_target_tab_id(tab_id);
-
-  CompositorMessage* details = message->mutable_compositor();
+  CompositorMessage* details;
+  scoped_ptr<BlimpMessage> message = CreateBlimpMessage(&details, tab_id);
   details->set_render_widget_id(rw_id);
   processor->ProcessMessage(std::move(message),
                             net::CompletionCallback());
diff --git a/blimp/common/BUILD.gn b/blimp/common/BUILD.gn
index 49afa02..72d23e1 100644
--- a/blimp/common/BUILD.gn
+++ b/blimp/common/BUILD.gn
@@ -9,6 +9,8 @@
     "blimp_common_export.h",
     "compositor/blimp_task_graph_runner.cc",
     "compositor/blimp_task_graph_runner.h",
+    "create_blimp_message.cc",
+    "create_blimp_message.h",
   ]
 
   defines = [ "BLIMP_COMMON_IMPLEMENTATION=1" ]
@@ -22,3 +24,17 @@
     "//ui/gl",
   ]
 }
+
+source_set("unit_tests") {
+  testonly = true
+
+  sources = [
+    "create_blimp_message_unittest.cc",
+  ]
+
+  deps = [
+    ":blimp_common",
+    "//blimp/common/proto",
+    "//testing/gtest",
+  ]
+}
diff --git a/blimp/common/create_blimp_message.cc b/blimp/common/create_blimp_message.cc
new file mode 100644
index 0000000..4d331ac
--- /dev/null
+++ b/blimp/common/create_blimp_message.cc
@@ -0,0 +1,46 @@
+// 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.
+
+#include "blimp/common/create_blimp_message.h"
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "blimp/common/proto/blimp_message.pb.h"
+#include "blimp/common/proto/compositor.pb.h"
+#include "blimp/common/proto/input.pb.h"
+#include "blimp/common/proto/render_widget.pb.h"
+
+namespace blimp {
+
+scoped_ptr<BlimpMessage> CreateBlimpMessage(
+    CompositorMessage** compositor_message,
+    int target_tab_id) {
+  DCHECK(compositor_message);
+  scoped_ptr<BlimpMessage> output(new BlimpMessage);
+  output->set_type(BlimpMessage::COMPOSITOR);
+  output->set_target_tab_id(target_tab_id);
+  *compositor_message = output->mutable_compositor();
+  return output;
+}
+
+scoped_ptr<BlimpMessage> CreateBlimpMessage(InputMessage** input_message) {
+  DCHECK(input_message);
+  scoped_ptr<BlimpMessage> output(new BlimpMessage);
+  output->set_type(BlimpMessage::INPUT);
+  *input_message = output->mutable_input();
+  return output;
+}
+
+scoped_ptr<BlimpMessage> CreateBlimpMessage(
+    RenderWidgetMessage** render_widget_message,
+    int target_tab_id) {
+  DCHECK(render_widget_message);
+  scoped_ptr<BlimpMessage> output(new BlimpMessage);
+  output->set_type(BlimpMessage::RENDER_WIDGET);
+  output->set_target_tab_id(target_tab_id);
+  *render_widget_message = output->mutable_render_widget();
+  return output;
+}
+
+}  // namespace blimp
diff --git a/blimp/common/create_blimp_message.h b/blimp/common/create_blimp_message.h
new file mode 100644
index 0000000..1e638d5
--- /dev/null
+++ b/blimp/common/create_blimp_message.h
@@ -0,0 +1,43 @@
+// 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.
+
+#ifndef BLIMP_COMMON_CREATE_BLIMP_MESSAGE_H_
+#define BLIMP_COMMON_CREATE_BLIMP_MESSAGE_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "blimp/common/blimp_common_export.h"
+
+namespace blimp {
+
+class BlimpMessage;
+class CompositorMessage;
+class InputMessage;
+class RenderWidgetMessage;
+
+// Suite of helper methods to simplify the repetitive task of creating
+// new BlimpMessages, initializing them, and extracting type-specific
+// inner messages.
+//
+//
+// Every specialization of CreateBlimpMessage returns an initialized
+// BlimpMessage object. In addition, a pointer to the type-specific inner
+// message is returned via the initial double-pointer parameter.
+//
+// Additional initialization arguments may be taken depending on the
+// message type.
+
+BLIMP_COMMON_EXPORT scoped_ptr<BlimpMessage> CreateBlimpMessage(
+    CompositorMessage** compositor_message,
+    int target_tab_id);
+
+BLIMP_COMMON_EXPORT scoped_ptr<BlimpMessage> CreateBlimpMessage(
+    InputMessage** input_message);
+
+BLIMP_COMMON_EXPORT scoped_ptr<BlimpMessage> CreateBlimpMessage(
+    RenderWidgetMessage** render_widget_message,
+    int target_tab_id);
+
+}  // namespace blimp
+
+#endif  // BLIMP_COMMON_CREATE_BLIMP_MESSAGE_H_
diff --git a/blimp/common/create_blimp_message_unittest.cc b/blimp/common/create_blimp_message_unittest.cc
new file mode 100644
index 0000000..1db89566
--- /dev/null
+++ b/blimp/common/create_blimp_message_unittest.cc
@@ -0,0 +1,44 @@
+// 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.
+
+#include "blimp/common/create_blimp_message.h"
+#include "blimp/common/proto/blimp_message.pb.h"
+#include "blimp/common/proto/compositor.pb.h"
+#include "blimp/common/proto/input.pb.h"
+#include "blimp/common/proto/render_widget.pb.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace blimp {
+namespace {
+
+const int kTabId = 1234;
+
+TEST(CreateBlimpMessageTest, CompositorMessage) {
+  CompositorMessage* details = nullptr;
+  scoped_ptr<BlimpMessage> message = CreateBlimpMessage(&details, kTabId);
+  EXPECT_NE(nullptr, details);
+  EXPECT_NE(nullptr, message);
+  EXPECT_EQ(details, message->mutable_compositor());
+  EXPECT_EQ(kTabId, message->target_tab_id());
+}
+
+TEST(CreateBlimpMessageTest, InputMessage) {
+  InputMessage* details = nullptr;
+  scoped_ptr<BlimpMessage> message = CreateBlimpMessage(&details);
+  EXPECT_NE(nullptr, details);
+  EXPECT_NE(nullptr, message);
+  EXPECT_EQ(details, message->mutable_input());
+}
+
+TEST(CreateBlimpMessageTest, RenderWidgetMessage) {
+  RenderWidgetMessage* details = nullptr;
+  scoped_ptr<BlimpMessage> message = CreateBlimpMessage(&details, kTabId);
+  EXPECT_NE(nullptr, details);
+  EXPECT_NE(nullptr, message);
+  EXPECT_EQ(details, message->mutable_render_widget());
+  EXPECT_EQ(kTabId, message->target_tab_id());
+}
+
+}  // namespace
+}  // namespace blimp
diff --git a/blimp/engine/browser/BUILD.gn b/blimp/engine/browser/BUILD.gn
index 714f092d..0bd678c4 100644
--- a/blimp/engine/browser/BUILD.gn
+++ b/blimp/engine/browser/BUILD.gn
@@ -24,6 +24,7 @@
 
   deps = [
     "//base",
+    "//blimp/common:blimp_common",
     "//blimp/common/proto",
     "//blimp/engine/ui",
     "//blimp/net:blimp_net",
@@ -51,6 +52,7 @@
     "//base",
     "//base/test:run_all_unittests",
     "//base/test:test_support",
+    "//blimp/common:blimp_common",
     "//blimp/common/proto",
     "//blimp/engine/common",
     "//blimp/net:blimp_net",
diff --git a/blimp/engine/browser/engine_render_widget_message_processor.cc b/blimp/engine/browser/engine_render_widget_message_processor.cc
index 00975d1..6e377dc 100644
--- a/blimp/engine/browser/engine_render_widget_message_processor.cc
+++ b/blimp/engine/browser/engine_render_widget_message_processor.cc
@@ -5,6 +5,7 @@
 #include "blimp/engine/browser/engine_render_widget_message_processor.h"
 
 #include "base/numerics/safe_conversions.h"
+#include "blimp/common/create_blimp_message.h"
 #include "blimp/common/proto/blimp_message.pb.h"
 #include "blimp/common/proto/compositor.pb.h"
 #include "blimp/common/proto/input.pb.h"
@@ -32,12 +33,9 @@
     const int tab_id) {
   render_widget_ids_[tab_id] = GetRenderWidgetId(tab_id) + 1;
 
-  scoped_ptr<BlimpMessage> blimp_message(new BlimpMessage);
-  blimp_message->set_target_tab_id(tab_id);
-
-  RenderWidgetMessage* render_widget_message =
-      blimp_message->mutable_render_widget();
-
+  RenderWidgetMessage* render_widget_message;
+  scoped_ptr<BlimpMessage> blimp_message =
+      CreateBlimpMessage(&render_widget_message, tab_id);
   render_widget_message->set_type(RenderWidgetMessage::INITIALIZE);
   render_widget_message->set_render_widget_id(GetRenderWidgetId(tab_id));
 
@@ -48,10 +46,10 @@
 void EngineRenderWidgetMessageProcessor::SendCompositorMessage(
     const int tab_id,
     const std::vector<uint8_t>& message) {
-  scoped_ptr<BlimpMessage> blimp_message(new BlimpMessage);
-  blimp_message->set_target_tab_id(tab_id);
+  CompositorMessage* compositor_message;
+  scoped_ptr<BlimpMessage> blimp_message =
+      CreateBlimpMessage(&compositor_message, tab_id);
 
-  CompositorMessage* compositor_message = blimp_message->mutable_compositor();
   uint32_t render_widget_id = GetRenderWidgetId(tab_id);
   DCHECK_LT(0U, render_widget_id);
   compositor_message->set_render_widget_id(render_widget_id);
diff --git a/blimp/engine/browser/engine_render_widget_message_processor_unittest.cc b/blimp/engine/browser/engine_render_widget_message_processor_unittest.cc
index 2d0da5e9..70d78fdc 100644
--- a/blimp/engine/browser/engine_render_widget_message_processor_unittest.cc
+++ b/blimp/engine/browser/engine_render_widget_message_processor_unittest.cc
@@ -7,6 +7,7 @@
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/numerics/safe_conversions.h"
+#include "blimp/common/create_blimp_message.h"
 #include "blimp/common/proto/blimp_message.pb.h"
 #include "blimp/common/proto/compositor.pb.h"
 #include "blimp/common/proto/render_widget.pb.h"
@@ -91,11 +92,8 @@
                              int tab_id,
                              uint32_t rw_id,
                              const std::vector<uint8_t>& payload) {
-  scoped_ptr<BlimpMessage> message(new BlimpMessage);
-  message->set_type(BlimpMessage::COMPOSITOR);
-  message->set_target_tab_id(tab_id);
-
-  CompositorMessage* details = message->mutable_compositor();
+  CompositorMessage* details;
+  scoped_ptr<BlimpMessage> message = CreateBlimpMessage(&details, tab_id);
   details->set_render_widget_id(rw_id);
   details->set_payload(payload.data(), base::checked_cast<int>(payload.size()));
   processor->ProcessMessage(std::move(message),
diff --git a/blimp/net/BUILD.gn b/blimp/net/BUILD.gn
index f20c77c..bd73b7a 100644
--- a/blimp/net/BUILD.gn
+++ b/blimp/net/BUILD.gn
@@ -51,6 +51,7 @@
 
   deps = [
     "//base",
+    "//blimp/common:blimp_common",
     "//blimp/common/proto",
     "//net",
   ]
@@ -82,6 +83,7 @@
     "blimp_message_multiplexer_unittest.cc",
     "blimp_message_output_buffer_unittest.cc",
     "blimp_message_pump_unittest.cc",
+    "client_connection_manager_unittest.cc",
     "engine_connection_manager_unittest.cc",
     "input_message_unittest.cc",
     "stream_packet_reader_unittest.cc",
diff --git a/blimp/net/blimp_message_output_buffer.cc b/blimp/net/blimp_message_output_buffer.cc
index 62cc259..c599ffaf 100644
--- a/blimp/net/blimp_message_output_buffer.cc
+++ b/blimp/net/blimp_message_output_buffer.cc
@@ -66,7 +66,7 @@
   DCHECK_GE(max_buffer_size_bytes_, current_buffer_size_bytes_);
 
   write_buffer_.push_back(
-      make_scoped_ptr(new BufferEntry(message.Pass(), callback)));
+      make_scoped_ptr(new BufferEntry(std::move(message), callback)));
 
   // Write the message
   if (write_buffer_.size() == 1 && output_processor_) {
@@ -115,7 +115,7 @@
 BlimpMessageOutputBuffer::BufferEntry::BufferEntry(
     scoped_ptr<BlimpMessage> message,
     net::CompletionCallback callback)
-    : message(message.Pass()), callback(callback) {}
+    : message(std::move(message)), callback(callback) {}
 
 BlimpMessageOutputBuffer::BufferEntry::~BufferEntry() {}
 
@@ -131,7 +131,7 @@
           << write_buffer_.front()->message->message_id()
           << ", type=" << message_to_write->type() << ")";
 
-  output_processor_->ProcessMessage(message_to_write.Pass(),
+  output_processor_->ProcessMessage(std::move(message_to_write),
                                     write_complete_cb_.callback());
   VLOG(3) << "Queue size: " << write_buffer_.size();
 }
diff --git a/blimp/net/client_connection_manager.cc b/blimp/net/client_connection_manager.cc
index 659f6a4..c8238e4 100644
--- a/blimp/net/client_connection_manager.cc
+++ b/blimp/net/client_connection_manager.cc
@@ -5,29 +5,55 @@
 #include "blimp/net/client_connection_manager.h"
 
 #include "base/logging.h"
+#include "blimp/net/blimp_connection.h"
+#include "blimp/net/blimp_transport.h"
+#include "blimp/net/connection_handler.h"
+#include "net/base/net_errors.h"
 
 namespace blimp {
 
 ClientConnectionManager::ClientConnectionManager(
-    ConnectionHandler* connection_handler) {
-  NOTIMPLEMENTED();
+    ConnectionHandler* connection_handler)
+    : connection_handler_(connection_handler) {
+  DCHECK(connection_handler_);
 }
 
-ClientConnectionManager::~ClientConnectionManager() {
-  NOTIMPLEMENTED();
+ClientConnectionManager::~ClientConnectionManager() {}
+
+void ClientConnectionManager::AddTransport(
+    scoped_ptr<BlimpTransport> transport) {
+  DCHECK(transport);
+  transports_.push_back(std::move(transport));
 }
 
 void ClientConnectionManager::Connect() {
-  NOTIMPLEMENTED();
+  // A |transport| added first is used first. When it fails to connect,
+  // the next transport is used.
+  DCHECK(!transports_.empty());
+  Connect(0);
 }
 
-void ClientConnectionManager::HandleConnection(
-    scoped_ptr<BlimpConnection> connection) {
-  NOTIMPLEMENTED();
+void ClientConnectionManager::Connect(int transport_index) {
+  if (static_cast<size_t>(transport_index) < transports_.size()) {
+    transports_[transport_index]->Connect(
+        base::Bind(&ClientConnectionManager::OnConnectResult,
+                   base::Unretained(this), transport_index));
+  } else {
+    // TODO(haibinlu): add an error reporting path out for this.
+    LOG(WARNING) << "All transports failed to connect";
+  }
 }
 
-void ClientConnectionManager::OnConnectionError(int error) {
-  NOTIMPLEMENTED();
+void ClientConnectionManager::OnConnectResult(int transport_index, int result) {
+  DCHECK_NE(result, net::ERR_IO_PENDING);
+  const auto& transport = transports_[transport_index];
+  if (result == net::OK) {
+    connection_handler_->HandleConnection(transport->TakeConnection());
+  } else {
+    DVLOG(1) << "Transport " << transport->GetName()
+             << " failed to connect:" << net::ErrorToString(result);
+    Connect(transport_index + 1);
+  }
 }
 
 }  // namespace blimp
diff --git a/blimp/net/client_connection_manager.h b/blimp/net/client_connection_manager.h
index ed9c9a9f..f259b62 100644
--- a/blimp/net/client_connection_manager.h
+++ b/blimp/net/client_connection_manager.h
@@ -5,37 +5,53 @@
 #ifndef BLIMP_NET_CLIENT_CONNECTION_MANAGER_H_
 #define BLIMP_NET_CLIENT_CONNECTION_MANAGER_H_
 
+#include <vector>
+
 #include "base/macros.h"
-#include "blimp/net/blimp_connection.h"
-#include "blimp/net/connection_error_observer.h"
-#include "blimp/net/connection_handler.h"
+#include "base/memory/scoped_ptr.h"
+#include "blimp/net/blimp_net_export.h"
 
 namespace blimp {
 
+class BlimpTransport;
+class ConnectionHandler;
+
 // Coordinates the channel creation and authentication workflows for
 // outgoing (Client) network connections.
-// Attempts to reconnect if an authenticated connection is
-// disconnected.
-class ClientConnectionManager : public ConnectionHandler,
-                                ConnectionErrorObserver {
-  // Caller is responsible for ensuring that |client_browser_session|
+//
+// TODO(haibinlu): cope with network changes that may potentially affect the
+// endpoint that we're trying to connect to.
+class BLIMP_NET_EXPORT ClientConnectionManager {
+ public:
+  // Caller is responsible for ensuring that |connection_handler|
   // outlives |this|.
   explicit ClientConnectionManager(ConnectionHandler* connection_handler);
 
-  ~ClientConnectionManager() override;
+  ~ClientConnectionManager();
 
+  // Adds a transport. All transports are expected to be added before invoking
+  // |Connect|.
+  void AddTransport(scoped_ptr<BlimpTransport> transport);
+
+  // Attempts to create a connection using any of the BlimpTransports in
+  // |transports_|.
+  // This will result in the handler being called back at-most-once.
+  //
+  // This is also a placeholder for automatic reconnection logic for common
+  // cases such as network switches, online/offline changes.
   void Connect();
 
-  // ConnectionHandler implementation.
-  // Handles a new connection and authenticates it before passing it on to
-  // the underlying ConnectionHandler.
-  void HandleConnection(scoped_ptr<BlimpConnection> connection) override;
-
-  // ConnectionErrorObserver implementation.
-  // Used to implement reconnection logic on unexpected disconnections.
-  void OnConnectionError(int error) override;
-
  private:
+  // Tries to connect using the BlimpTransport specified at |transport_index|.
+  void Connect(int transport_index);
+
+  // Callback invoked by transports_[transport_index] to indicate that it has a
+  // connection ready to be authenticated or there is an error.
+  void OnConnectResult(int transport_index, int result);
+
+  ConnectionHandler* connection_handler_;
+  std::vector<scoped_ptr<BlimpTransport>> transports_;
+
   DISALLOW_COPY_AND_ASSIGN(ClientConnectionManager);
 };
 
diff --git a/blimp/net/client_connection_manager_unittest.cc b/blimp/net/client_connection_manager_unittest.cc
new file mode 100644
index 0000000..31d6a2bff
--- /dev/null
+++ b/blimp/net/client_connection_manager_unittest.cc
@@ -0,0 +1,104 @@
+// 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.
+
+#include <stddef.h>
+#include <string>
+
+#include "base/callback_helpers.h"
+#include "base/message_loop/message_loop.h"
+#include "blimp/net/blimp_connection.h"
+#include "blimp/net/blimp_transport.h"
+#include "blimp/net/client_connection_manager.h"
+#include "blimp/net/test_common.h"
+#include "net/base/completion_callback.h"
+#include "net/base/net_errors.h"
+#include "net/base/test_completion_callback.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::_;
+using testing::Eq;
+using testing::Return;
+using testing::SaveArg;
+
+namespace blimp {
+
+class ClientConnectionManagerTest : public testing::Test {
+ public:
+  ClientConnectionManagerTest()
+      : manager_(new ClientConnectionManager(&connection_handler_)),
+        transport1_(new testing::StrictMock<MockTransport>),
+        transport2_(new testing::StrictMock<MockTransport>),
+        connection_(
+            new BlimpConnection(make_scoped_ptr(new MockPacketReader),
+                                make_scoped_ptr(new MockPacketWriter))) {}
+
+  ~ClientConnectionManagerTest() override {}
+
+ protected:
+  base::MessageLoop message_loop_;
+  testing::StrictMock<MockConnectionHandler> connection_handler_;
+  scoped_ptr<ClientConnectionManager> manager_;
+  scoped_ptr<testing::StrictMock<MockTransport>> transport1_;
+  scoped_ptr<testing::StrictMock<MockTransport>> transport2_;
+  scoped_ptr<BlimpConnection> connection_;
+};
+
+// The 1st transport connects, and the 2nd transport is not used.
+TEST_F(ClientConnectionManagerTest, FirstTransportConnects) {
+  net::CompletionCallback connect_cb_1;
+  EXPECT_CALL(*transport1_, Connect(_)).WillOnce(SaveArg<0>(&connect_cb_1));
+  EXPECT_CALL(connection_handler_, HandleConnectionPtr(Eq(connection_.get())));
+  EXPECT_CALL(*transport1_, TakeConnectionPtr())
+      .WillOnce(Return(connection_.release()));
+
+  ASSERT_TRUE(connect_cb_1.is_null());
+  manager_->AddTransport(std::move(transport1_));
+  manager_->AddTransport(std::move(transport2_));
+  manager_->Connect();
+  ASSERT_FALSE(connect_cb_1.is_null());
+  base::ResetAndReturn(&connect_cb_1).Run(net::OK);
+}
+
+// The 1st transport fails to connect, and the 2nd transport connects.
+TEST_F(ClientConnectionManagerTest, SecondTransportConnects) {
+  net::CompletionCallback connect_cb_1;
+  EXPECT_CALL(*transport1_, Connect(_)).WillOnce(SaveArg<0>(&connect_cb_1));
+  net::CompletionCallback connect_cb_2;
+  EXPECT_CALL(*transport2_, Connect(_)).WillOnce(SaveArg<0>(&connect_cb_2));
+  EXPECT_CALL(connection_handler_, HandleConnectionPtr(Eq(connection_.get())));
+  EXPECT_CALL(*transport2_, TakeConnectionPtr())
+      .WillOnce(Return(connection_.release()));
+
+  ASSERT_TRUE(connect_cb_1.is_null());
+  ASSERT_TRUE(connect_cb_2.is_null());
+  manager_->AddTransport(std::move(transport1_));
+  manager_->AddTransport(std::move(transport2_));
+  manager_->Connect();
+  ASSERT_FALSE(connect_cb_1.is_null());
+  base::ResetAndReturn(&connect_cb_1).Run(net::ERR_FAILED);
+  ASSERT_FALSE(connect_cb_2.is_null());
+  base::ResetAndReturn(&connect_cb_2).Run(net::OK);
+}
+
+// Both transports fail to connect.
+TEST_F(ClientConnectionManagerTest, BothTransportsFailToConnect) {
+  net::CompletionCallback connect_cb_1;
+  EXPECT_CALL(*transport1_, Connect(_)).WillOnce(SaveArg<0>(&connect_cb_1));
+  net::CompletionCallback connect_cb_2;
+  EXPECT_CALL(*transport2_, Connect(_)).WillOnce(SaveArg<0>(&connect_cb_2));
+
+  ASSERT_TRUE(connect_cb_1.is_null());
+  ASSERT_TRUE(connect_cb_2.is_null());
+  manager_->AddTransport(std::move(transport1_));
+  manager_->AddTransport(std::move(transport2_));
+  manager_->Connect();
+  ASSERT_FALSE(connect_cb_1.is_null());
+  ASSERT_TRUE(connect_cb_2.is_null());
+  base::ResetAndReturn(&connect_cb_1).Run(net::ERR_FAILED);
+  ASSERT_FALSE(connect_cb_2.is_null());
+  base::ResetAndReturn(&connect_cb_2).Run(net::ERR_FAILED);
+}
+
+}  // namespace blimp
diff --git a/blimp/net/engine_connection_manager.cc b/blimp/net/engine_connection_manager.cc
index 549caa3..053508e 100644
--- a/blimp/net/engine_connection_manager.cc
+++ b/blimp/net/engine_connection_manager.cc
@@ -13,7 +13,9 @@
 
 EngineConnectionManager::EngineConnectionManager(
     ConnectionHandler* connection_handler)
-    : connection_handler_(connection_handler) {}
+    : connection_handler_(connection_handler) {
+  DCHECK(connection_handler_);
+}
 
 EngineConnectionManager::~EngineConnectionManager() {}
 
diff --git a/blimp/net/input_message_generator.cc b/blimp/net/input_message_generator.cc
index ae0eef04d..507690c2 100644
--- a/blimp/net/input_message_generator.cc
+++ b/blimp/net/input_message_generator.cc
@@ -5,6 +5,7 @@
 #include "blimp/net/input_message_generator.h"
 
 #include "base/logging.h"
+#include "blimp/common/create_blimp_message.h"
 #include "blimp/common/proto/blimp_message.pb.h"
 #include "blimp/common/proto/input.pb.h"
 #include "blimp/net/blimp_message_processor.h"
@@ -113,9 +114,8 @@
 
 scoped_ptr<BlimpMessage> InputMessageGenerator::GenerateMessage(
     const blink::WebInputEvent& event) {
-  scoped_ptr<BlimpMessage> message(new BlimpMessage);
-  message->set_type(BlimpMessage::INPUT);
-  InputMessage* details = message->mutable_input();
+  InputMessage* details;
+  scoped_ptr<BlimpMessage> message = CreateBlimpMessage(&details);
 
   switch (event.type) {
     case blink::WebInputEvent::Type::GestureScrollBegin:
diff --git a/build/android/PRESUBMIT.py b/build/android/PRESUBMIT.py
index 5e4c988e..38b2f01 100644
--- a/build/android/PRESUBMIT.py
+++ b/build/android/PRESUBMIT.py
@@ -12,9 +12,11 @@
 def CommonChecks(input_api, output_api):
   output = []
 
+  build_android_dir = input_api.PresubmitLocalPath()
+
   def J(*dirs):
     """Returns a path relative to presubmit directory."""
-    return input_api.os_path.join(input_api.PresubmitLocalPath(), *dirs)
+    return input_api.os_path.join(build_android_dir, *dirs)
 
   build_pys = [
       r'gyp/.*\.py$',
@@ -40,7 +42,7 @@
 
   pylib_test_env = dict(input_api.environ)
   pylib_test_env.update({
-      'PYTHONPATH': input_api.PresubmitLocalPath(),
+      'PYTHONPATH': build_android_dir,
       'PYTHONDONTWRITEBYTECODE': '1',
   })
   output.extend(input_api.canned_checks.RunUnitTests(
@@ -48,13 +50,6 @@
       output_api,
       unit_tests=[
           J('.', 'emma_coverage_stats_test.py'),
-          J('devil', 'android', 'fastboot_utils_test.py'),
-          J('devil', 'android', 'battery_utils_test.py'),
-          J('devil', 'android', 'device_utils_test.py'),
-          J('devil', 'android', 'md5sum_test.py'),
-          J('devil', 'android', 'logcat_monitor_test.py'),
-          J('devil', 'utils', 'cmd_helper_test.py'),
-          J('devil', 'utils', 'timeout_retry_unittest.py'),
           J('gyp', 'util', 'md5_check_test.py'),
           J('play_services', 'update_test.py'),
           J('pylib', 'base', 'test_dispatcher_unittest.py'),
@@ -64,6 +59,26 @@
           J('pylib', 'results', 'json_results_test.py'),
       ],
       env=pylib_test_env))
+
+
+  devil_test_env = dict(pylib_test_env)
+  devil_test_env.update({
+      'DEVIL_ENV_CONFIG':
+          input_api.os_path.join(build_android_dir, 'devil_chromium.json')
+  })
+  output.extend(input_api.canned_checks.RunUnitTests(
+      input_api,
+      output_api,
+      unit_tests=[
+          J('devil', 'android', 'battery_utils_test.py'),
+          J('devil', 'android', 'device_utils_test.py'),
+          J('devil', 'android', 'fastboot_utils_test.py'),
+          J('devil', 'android', 'md5sum_test.py'),
+          J('devil', 'android', 'logcat_monitor_test.py'),
+          J('devil', 'utils', 'cmd_helper_test.py'),
+          J('devil', 'utils', 'timeout_retry_unittest.py'),
+      ],
+      env=devil_test_env))
   return output
 
 
diff --git a/build/android/adb_gdb b/build/android/adb_gdb
index 15320df..78bc182 100755
--- a/build/android/adb_gdb
+++ b/build/android/adb_gdb
@@ -949,11 +949,17 @@
 
 # Select correct app_process for architecture.
 case $TARGET_ARCH in
-      arm|x86|mips) GDBEXEC=app_process;;
+      arm|x86|mips) GDBEXEC=app_process32;;
       arm64|x86_64) GDBEXEC=app_process64;;
       *) fail_panic "Unknown app_process for architecture!";;
 esac
 
+# Default to app_process if bit-width specific process isn't found.
+adb_shell ls /system/bin/$GDBEXEC
+if [ $? != 0 ]; then
+    GDBEXEC=app_process
+fi
+
 # Detect AddressSanitizer setup on the device. In that case app_process is a
 # script, and the real executable is app_process.real.
 GDBEXEC_ASAN=app_process.real
diff --git a/build/android/adb_install_apk.py b/build/android/adb_install_apk.py
index a816bd4..0914bc1 100755
--- a/build/android/adb_install_apk.py
+++ b/build/android/adb_install_apk.py
@@ -12,6 +12,8 @@
 import os
 import sys
 
+import devil_chromium
+
 from devil.android import apk_helper
 from devil.android import device_blacklist
 from devil.android import device_errors
@@ -62,6 +64,8 @@
   run_tests_helper.SetLogLevel(args.verbose)
   constants.SetBuildType(args.build_type)
 
+  devil_chromium.Initialize(output_directory=constants.GetOutDirectory())
+
   apk = args.apk_path or args.apk_name
   if not apk.endswith('.apk'):
     apk += '.apk'
diff --git a/build/android/buildbot/bb_device_status_check.py b/build/android/buildbot/bb_device_status_check.py
index 6dd5ca5..eb1e5d9 100755
--- a/build/android/buildbot/bb_device_status_check.py
+++ b/build/android/buildbot/bb_device_status_check.py
@@ -16,6 +16,7 @@
 import sys
 
 sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
+import devil_chromium
 from devil.android import battery_utils
 from devil.android import device_blacklist
 from devil.android import device_errors
@@ -310,6 +311,8 @@
 
   run_tests_helper.SetLogLevel(args.verbose)
 
+  devil_chromium.Initialize()
+
   blacklist = (device_blacklist.Blacklist(args.blacklist_file)
                if args.blacklist_file
                else None)
diff --git a/build/android/devil/android/battery_utils_test.py b/build/android/devil/android/battery_utils_test.py
index af18e89..cf0a15fd 100755
--- a/build/android/devil/android/battery_utils_test.py
+++ b/build/android/devil/android/battery_utils_test.py
@@ -10,20 +10,18 @@
 # pylint: disable=protected-access,unused-argument
 
 import logging
-import os
 import sys
 import unittest
 
+from devil import devil_env
 from devil.android import battery_utils
 from devil.android import device_errors
 from devil.android import device_utils
 from devil.android import device_utils_test
 from devil.utils import mock_calls
-from pylib import constants
 
-sys.path.append(os.path.join(
-    constants.DIR_SOURCE_ROOT, 'third_party', 'pymock'))
-import mock # pylint: disable=F0401
+sys.path.append(devil_env.config.LocalPath('pymock'))
+import mock # pylint: disable=import-error
 
 _DUMPSYS_OUTPUT = [
     '9,0,i,uid,1000,test_package1',
diff --git a/build/android/devil/android/device_utils.py b/build/android/devil/android/device_utils.py
index 400c517..2c640b78 100644
--- a/build/android/devil/android/device_utils.py
+++ b/build/android/devil/android/device_utils.py
@@ -22,6 +22,7 @@
 import zipfile
 
 from devil import base_error
+from devil import devil_env
 from devil.utils import cmd_helper
 from devil.android import apk_helper
 from devil.android import device_signal
@@ -41,7 +42,6 @@
 from devil.utils import reraiser_thread
 from devil.utils import timeout_retry
 from devil.utils import zip_utils
-from pylib import constants
 from pylib.device.commands import install_commands
 
 _DEFAULT_TIMEOUT = 30
@@ -107,7 +107,8 @@
     A list containing the configured AVDs.
   """
   lines = cmd_helper.GetCmdOutput([
-      os.path.join(constants.ANDROID_SDK_ROOT, 'tools', 'android'),
+      os.path.join(devil_env.config.LocalPath('android_sdk'),
+                   'tools', 'android'),
       'list', 'avd']).splitlines()
   avds = []
   for line in lines:
diff --git a/build/android/devil/android/device_utils_test.py b/build/android/devil/android/device_utils_test.py
index 09c527ef..bed9437d 100755
--- a/build/android/devil/android/device_utils_test.py
+++ b/build/android/devil/android/device_utils_test.py
@@ -11,10 +11,10 @@
 # pylint: disable=unused-argument
 
 import logging
-import os
 import sys
 import unittest
 
+from devil import devil_env
 from devil.android import device_errors
 from devil.android import device_signal
 from devil.android import device_utils
@@ -23,11 +23,9 @@
 from devil.android.sdk import version_codes
 from devil.utils import cmd_helper
 from devil.utils import mock_calls
-from pylib import constants
 
-sys.path.append(os.path.join(
-    constants.DIR_SOURCE_ROOT, 'third_party', 'pymock'))
-import mock # pylint: disable=F0401
+sys.path.append(devil_env.config.LocalPath('pymock'))
+import mock # pylint: disable=import-error
 
 
 class _MockApkHelper(object):
@@ -71,17 +69,21 @@
 class DeviceUtilsGetAVDsTest(mock_calls.TestCase):
 
   def testGetAVDs(self):
-    with self.assertCall(
-        mock.call.devil.utils.cmd_helper.GetCmdOutput(
-            [mock.ANY, 'list', 'avd']),
-        'Available Android Virtual Devices:\n'
-        '    Name: my_android5.0\n'
-        '    Path: /some/path/to/.android/avd/my_android5.0.avd\n'
-        '  Target: Android 5.0 (API level 21)\n'
-        ' Tag/ABI: default/x86\n'
-        '    Skin: WVGA800\n'):
-      self.assertEquals(['my_android5.0'],
-                        device_utils.GetAVDs())
+    mocked_attrs = {
+      'android_sdk': '/my/sdk/path'
+    }
+    with mock.patch('devil.devil_env._Environment.LocalPath',
+                    mock.Mock(side_effect=lambda a: mocked_attrs[a])):
+      with self.assertCall(
+          mock.call.devil.utils.cmd_helper.GetCmdOutput(
+              [mock.ANY, 'list', 'avd']),
+          'Available Android Virtual Devices:\n'
+          '    Name: my_android5.0\n'
+          '    Path: /some/path/to/.android/avd/my_android5.0.avd\n'
+          '  Target: Android 5.0 (API level 21)\n'
+          ' Tag/ABI: default/x86\n'
+          '    Skin: WVGA800\n'):
+        self.assertEquals(['my_android5.0'], device_utils.GetAVDs())
 
 
 class DeviceUtilsRestartServerTest(mock_calls.TestCase):
diff --git a/build/android/devil/android/fastboot_utils_test.py b/build/android/devil/android/fastboot_utils_test.py
index ff2c501..67d5c64 100755
--- a/build/android/devil/android/fastboot_utils_test.py
+++ b/build/android/devil/android/fastboot_utils_test.py
@@ -11,19 +11,17 @@
 
 import io
 import logging
-import os
 import sys
 import unittest
 
+from devil import devil_env
 from devil.android import device_errors
 from devil.android import device_utils
 from devil.android import fastboot_utils
 from devil.android.sdk import fastboot
 from devil.utils import mock_calls
-from pylib import constants
 
-sys.path.append(os.path.join(
-    constants.DIR_SOURCE_ROOT, 'third_party', 'pymock'))
+sys.path.append(devil_env.config.LocalPath('pymock'))
 import mock # pylint: disable=import-error
 
 _BOARD = 'board_type'
diff --git a/build/android/devil/android/logcat_monitor_test.py b/build/android/devil/android/logcat_monitor_test.py
index 2b7969c4..923c671 100755
--- a/build/android/devil/android/logcat_monitor_test.py
+++ b/build/android/devil/android/logcat_monitor_test.py
@@ -6,17 +6,15 @@
 # pylint: disable=protected-access
 
 import itertools
-import os
 import sys
 import unittest
 
+from devil import devil_env
 from devil.android import logcat_monitor
 from devil.android.sdk import adb_wrapper
-from pylib import constants
 
-sys.path.append(os.path.join(
-    constants.DIR_SOURCE_ROOT, 'third_party', 'pymock'))
-import mock # pylint: disable=F0401
+sys.path.append(devil_env.config.LocalPath('pymock'))
+import mock # pylint: disable=import-error
 
 
 def _CreateTestLog(raw_logcat=None):
diff --git a/build/android/devil/android/md5sum.py b/build/android/devil/android/md5sum.py
index dbd988f..bae134d 100644
--- a/build/android/devil/android/md5sum.py
+++ b/build/android/devil/android/md5sum.py
@@ -6,9 +6,9 @@
 import posixpath
 import re
 
+from devil import devil_env
 from devil.android import device_errors
 from devil.utils import cmd_helper
-from pylib import constants
 
 MD5SUM_DEVICE_LIB_PATH = '/data/local/tmp/md5sum'
 MD5SUM_DEVICE_BIN_PATH = MD5SUM_DEVICE_LIB_PATH + '/md5sum_bin'
@@ -30,8 +30,7 @@
   if isinstance(paths, basestring):
     paths = [paths]
 
-  md5sum_bin_host_path = os.path.join(
-      constants.GetOutDirectory(), 'md5sum_bin_host')
+  md5sum_bin_host_path = devil_env.config.FetchPath('md5sum_host')
   if not os.path.exists(md5sum_bin_host_path):
     raise IOError('File not built: %s' % md5sum_bin_host_path)
   out = cmd_helper.GetCmdOutput([md5sum_bin_host_path] + [p for p in paths])
@@ -58,8 +57,12 @@
   # Allow generators
   paths = list(paths)
 
-  md5sum_dist_path = os.path.join(constants.GetOutDirectory(), 'md5sum_dist')
-  md5sum_dist_bin_path = os.path.join(md5sum_dist_path, 'md5sum_bin')
+  md5sum_dist_path = devil_env.config.FetchPath('md5sum_device', device=device)
+
+  if os.path.isdir(md5sum_dist_path):
+    md5sum_dist_bin_path = os.path.join(md5sum_dist_path, 'md5sum_bin')
+  else:
+    md5sum_dist_bin_path = md5sum_dist_path
 
   if not os.path.exists(md5sum_dist_path):
     raise IOError('File not built: %s' % md5sum_dist_path)
@@ -95,7 +98,13 @@
       # actually fail. So, wipe the directory first.
       device.RunShellCommand(['rm', '-rf', MD5SUM_DEVICE_LIB_PATH],
                              as_root=True, check_return=True)
-      device.adb.Push(md5sum_dist_path, MD5SUM_DEVICE_LIB_PATH)
+      if os.path.isdir(md5sum_dist_path):
+        device.adb.Push(md5sum_dist_path, MD5SUM_DEVICE_LIB_PATH)
+      else:
+        mkdir_cmd = 'a=%s;[[ -e $a ]] || mkdir $a' % MD5SUM_DEVICE_LIB_PATH
+        device.RunShellCommand(mkdir_cmd, check_return=True)
+        device.adb.Push(md5sum_dist_bin_path, MD5SUM_DEVICE_BIN_PATH)
+
       out = device.RunShellCommand(md5sum_script, check_return=True)
     else:
       raise
diff --git a/build/android/devil/android/md5sum_test.py b/build/android/devil/android/md5sum_test.py
index e9481b65..86023f7a 100755
--- a/build/android/devil/android/md5sum_test.py
+++ b/build/android/devil/android/md5sum_test.py
@@ -7,25 +7,29 @@
 import sys
 import unittest
 
+from devil import devil_env
 from devil.android import device_errors
 from devil.android import md5sum
-from pylib import constants
 
-sys.path.append(
-    os.path.join(constants.DIR_SOURCE_ROOT, 'third_party', 'pymock'))
+sys.path.append(devil_env.config.LocalPath('pymock'))
 import mock # pylint: disable=import-error
 
 TEST_OUT_DIR = os.path.join('test', 'out', 'directory')
 HOST_MD5_EXECUTABLE = os.path.join(TEST_OUT_DIR, 'md5sum_bin_host')
+MD5_DIST = os.path.join(TEST_OUT_DIR, 'md5sum_dist')
 
 class Md5SumTest(unittest.TestCase):
 
   def setUp(self):
+    mocked_attrs = {
+      'md5sum_host': HOST_MD5_EXECUTABLE,
+      'md5sum_device': MD5_DIST,
+    }
     self._patchers = [
-        mock.patch('pylib.constants.GetOutDirectory',
-                   new=mock.Mock(return_value=TEST_OUT_DIR)),
-        mock.patch('os.path.exists',
-                   new=mock.Mock(return_value=True)),
+      mock.patch('devil.devil_env._Environment.FetchPath',
+                 mock.Mock(side_effect=lambda a, device=None: mocked_attrs[a])),
+      mock.patch('os.path.exists',
+                 new=mock.Mock(return_value=True)),
     ]
     for p in self._patchers:
       p.start()
@@ -217,7 +221,8 @@
     device.RunShellCommand = mock.Mock(
         side_effect=(error, '', device_md5sum_output))
 
-    with mock.patch('os.path.getsize', return_value=1337):
+    with mock.patch('os.path.isdir', return_value=True), (
+         mock.patch('os.path.getsize', return_value=1337)):
       out = md5sum.CalculateDeviceMd5Sums(test_path, device)
       self.assertEquals(1, len(out))
       self.assertTrue('/storage/emulated/legacy/test/file.dat' in out)
diff --git a/build/android/devil/android/sdk/aapt.py b/build/android/devil/android/sdk/aapt.py
index 1c051e0c..7ae3a93 100644
--- a/build/android/devil/android/sdk/aapt.py
+++ b/build/android/devil/android/sdk/aapt.py
@@ -4,12 +4,13 @@
 
 """This module wraps the Android Asset Packaging Tool."""
 
-import os
-
+from devil.android.sdk import build_tools
 from devil.utils import cmd_helper
-from pylib import constants
+from devil.utils import lazy
 
-_AAPT_PATH = os.path.join(constants.ANDROID_SDK_TOOLS, 'aapt')
+
+_aapt_path = lazy.WeakConstant(lambda: build_tools.GetPath('aapt'))
+
 
 def _RunAaptCmd(args):
   """Runs an aapt command.
@@ -20,13 +21,14 @@
   Returns:
     The output of the command.
   """
-  cmd = [_AAPT_PATH] + args
+  cmd = [_aapt_path.read()] + args
   status, output = cmd_helper.GetCmdStatusAndOutput(cmd)
   if status != 0:
     raise Exception('Failed running aapt command: "%s" with output "%s".' %
                     (' '.join(cmd), output))
   return output
 
+
 def Dump(what, apk, assets=None):
   """Returns the output of the aapt dump command.
 
diff --git a/build/android/devil/android/sdk/adb_wrapper.py b/build/android/devil/android/sdk/adb_wrapper.py
index 3ab7ddc..c184c77 100644
--- a/build/android/devil/android/sdk/adb_wrapper.py
+++ b/build/android/devil/android/sdk/adb_wrapper.py
@@ -14,11 +14,15 @@
 import os
 import re
 
+from devil import devil_env
 from devil.android import decorators
 from devil.android import device_errors
 from devil.utils import cmd_helper
+from devil.utils import lazy
 from devil.utils import timeout_retry
-from pylib import constants
+
+with devil_env.SysPath(devil_env.CATAPULT_BASE_PATH):
+  from catapult_base import dependency_manager # pylint: disable=import-error
 
 
 _DEFAULT_TIMEOUT = 30
@@ -42,6 +46,21 @@
     raise IOError(errno.ENOENT, os.strerror(errno.ENOENT), path)
 
 
+def _FindAdb():
+  try:
+    return devil_env.config.LocalPath('adb')
+  except dependency_manager.NoPathFoundError:
+    pass
+
+  try:
+    return os.path.join(devil_env.config.LocalPath('android_sdk'),
+                        'platform-tools', 'adb')
+  except dependency_manager.NoPathFoundError:
+    pass
+
+  return devil_env.config.FetchPath('adb')
+
+
 DeviceStat = collections.namedtuple('DeviceStat',
                                     ['st_mode', 'st_size', 'st_time'])
 
@@ -49,6 +68,8 @@
 class AdbWrapper(object):
   """A wrapper around a local Android Debug Bridge executable."""
 
+  _adb_path = lazy.WeakConstant(_FindAdb)
+
   def __init__(self, device_serial):
     """Initializes the AdbWrapper.
 
@@ -59,19 +80,21 @@
       raise ValueError('A device serial must be specified')
     self._device_serial = str(device_serial)
 
-  # pylint: disable=unused-argument
+  @classmethod
+  def GetAdbPath(cls):
+    return cls._adb_path.read()
+
   @classmethod
   def _BuildAdbCmd(cls, args, device_serial, cpu_affinity=None):
     if cpu_affinity is not None:
       cmd = ['taskset', '-c', str(cpu_affinity)]
     else:
       cmd = []
-    cmd.append(constants.GetAdbPath())
+    cmd.append(cls.GetAdbPath())
     if device_serial is not None:
       cmd.extend(['-s', device_serial])
     cmd.extend(args)
     return cmd
-  # pylint: enable=unused-argument
 
   # pylint: disable=unused-argument
   @classmethod
diff --git a/build/android/devil/android/sdk/build_tools.py b/build/android/devil/android/sdk/build_tools.py
new file mode 100644
index 0000000..6965dd4
--- /dev/null
+++ b/build/android/devil/android/sdk/build_tools.py
@@ -0,0 +1,51 @@
+# 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.
+
+import os
+
+from devil import devil_env
+from devil.utils import lazy
+
+with devil_env.SysPath(devil_env.CATAPULT_BASE_PATH):
+  from catapult_base import dependency_manager # pylint: disable=import-error
+
+
+def GetPath(build_tool):
+  try:
+    return devil_env.config.LocalPath(build_tool)
+  except dependency_manager.NoPathFoundError:
+    pass
+
+  try:
+    return _PathInLocalSdk(build_tool)
+  except dependency_manager.NoPathFoundError:
+    pass
+
+  return devil_env.config.FetchPath(build_tool)
+
+
+def _PathInLocalSdk(build_tool):
+  build_tools_path = _build_tools_path.read()
+  return (os.path.join(build_tools_path, build_tool) if build_tools_path
+          else None)
+
+
+def _FindBuildTools():
+  android_sdk_path = devil_env.config.LocalPath('android_sdk')
+  if not android_sdk_path:
+    return None
+
+  build_tools_contents = os.listdir(
+      os.path.join(android_sdk_path, 'build-tools'))
+
+  if not build_tools_contents:
+    return None
+  else:
+    if len(build_tools_contents) > 1:
+      build_tools_contents.sort()
+    return os.path.join(android_sdk_path, 'build-tools',
+                        build_tools_contents[-1])
+
+
+_build_tools_path = lazy.WeakConstant(_FindBuildTools)
diff --git a/build/android/devil/android/sdk/dexdump.py b/build/android/devil/android/sdk/dexdump.py
index 48d810f..992366e8 100644
--- a/build/android/devil/android/sdk/dexdump.py
+++ b/build/android/devil/android/sdk/dexdump.py
@@ -2,12 +2,13 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import os
-
+from devil.android.sdk import build_tools
 from devil.utils import cmd_helper
-from pylib import constants
+from devil.utils import lazy
 
-_DEXDUMP_PATH = os.path.join(constants.ANDROID_SDK_TOOLS, 'dexdump')
+
+_dexdump_path = lazy.WeakConstant(lambda: build_tools.GetPath('dexdump'))
+
 
 def DexDump(dexfiles, file_summary=False):
   """A wrapper around the Android SDK's dexdump tool.
@@ -22,7 +23,7 @@
   # TODO(jbudorick): Add support for more options as necessary.
   if isinstance(dexfiles, basestring):
     dexfiles = [dexfiles]
-  args = [_DEXDUMP_PATH] + dexfiles
+  args = [_dexdump_path.read()] + dexfiles
   if file_summary:
     args.append('-f')
 
diff --git a/build/android/devil/android/sdk/fastboot.py b/build/android/devil/android/sdk/fastboot.py
index cfc566a..aebff203 100644
--- a/build/android/devil/android/sdk/fastboot.py
+++ b/build/android/devil/android/sdk/fastboot.py
@@ -11,19 +11,21 @@
 
 import os
 
+from devil import devil_env
 from devil.android import decorators
 from devil.android import device_errors
 from devil.utils import cmd_helper
-from pylib import constants
+from devil.utils import lazy
 
-_FASTBOOT_CMD = os.path.join(
-    constants.ANDROID_SDK_ROOT, 'platform-tools', 'fastboot')
 _DEFAULT_TIMEOUT = 30
 _DEFAULT_RETRIES = 3
 _FLASH_TIMEOUT = _DEFAULT_TIMEOUT * 10
 
 class Fastboot(object):
 
+  _fastboot_path = lazy.WeakConstant(lambda: os.path.join(
+      devil_env.config.LocalPath('android_sdk'), 'platform-tools', 'adb'))
+
   def __init__(self, device_serial, default_timeout=_DEFAULT_TIMEOUT,
                default_retries=_DEFAULT_RETRIES):
     """Initializes the FastbootWrapper.
@@ -51,7 +53,7 @@
       TypeError: If cmd is not of type list.
     """
     if type(cmd) == list:
-      cmd = [_FASTBOOT_CMD, '-s', self._device_serial] + cmd
+      cmd = [self._fastboot_path.read(), '-s', self._device_serial] + cmd
     else:
       raise TypeError(
           'Command for _RunFastbootCommand must be a list.')
diff --git a/build/android/devil/android/sdk/shared_prefs_test.py b/build/android/devil/android/sdk/shared_prefs_test.py
index 63d9aec..6eba2295 100755
--- a/build/android/devil/android/sdk/shared_prefs_test.py
+++ b/build/android/devil/android/sdk/shared_prefs_test.py
@@ -8,16 +8,14 @@
 """
 
 import logging
-import os
 import sys
 import unittest
 
+from devil import devil_env
 from devil.android import device_utils
 from devil.android.sdk import shared_prefs
-from pylib import constants
 
-sys.path.append(os.path.join(
-    constants.DIR_SOURCE_ROOT, 'third_party', 'pymock'))
+sys.path.append(devil_env.config.LocalPath('pymock'))
 import mock # pylint: disable=import-error
 
 
diff --git a/build/android/devil/android/sdk/split_select.py b/build/android/devil/android/sdk/split_select.py
index 47fcea3c..b47a21f 100644
--- a/build/android/devil/android/sdk/split_select.py
+++ b/build/android/devil/android/sdk/split_select.py
@@ -4,12 +4,14 @@
 
 """This module wraps Android's split-select tool."""
 
-import os
-
+from devil.android.sdk import build_tools
 from devil.utils import cmd_helper
-from pylib import constants
+from devil.utils import lazy
 
-_SPLIT_SELECT_PATH = os.path.join(constants.ANDROID_SDK_TOOLS, 'split-select')
+
+_split_select_path = lazy.WeakConstant(
+    lambda: build_tools.GetPath('split-select'))
+
 
 def _RunSplitSelectCmd(args):
   """Runs a split-select command.
@@ -20,7 +22,7 @@
   Returns:
     The output of the command.
   """
-  cmd = [_SPLIT_SELECT_PATH] + args
+  cmd = [_split_select_path.read()] + args
   status, output = cmd_helper.GetCmdStatusAndOutput(cmd)
   if status != 0:
     raise Exception('Failed running command "%s" with output "%s".' %
diff --git a/build/android/devil/devil_dependencies.json b/build/android/devil/devil_dependencies.json
new file mode 100644
index 0000000..867d8cbd
--- /dev/null
+++ b/build/android/devil/devil_dependencies.json
@@ -0,0 +1,116 @@
+{
+  "config_type": "BaseConfig",
+  "dependencies": {
+    "aapt": {
+      "cloud_storage_bucket": "chromium-telemetry",
+      "cloud_storage_base_folder": "binary_dependencies",
+      "file_info": {
+        "android_host": {
+          "cloud_storage_hash": "7448de3cb5e834afdedeaad8b40ba63ac53f3dc4",
+          "download_path": "../bin/aapt"
+        }
+      }
+    },
+    "adb": {
+      "cloud_storage_bucket": "chromium-telemetry",
+      "cloud_storage_base_folder": "binary_dependencies",
+      "file_info": {
+        "android_host": {
+          "cloud_storage_hash": "0c2043552619c8ec8bb5d986ba75703a598611fc",
+          "download_path": "../bin/adb"
+        }
+      }
+    },
+    "android_build_tools_libc++": {
+      "cloud_storage_bucket": "chromium-telemetry",
+      "cloud_storage_base_folder": "binary_dependencies",
+      "file_info": {
+        "android_host": {
+          "cloud_storage_hash": "52d150a7ccde835f38b4337392152f3013d5f303",
+          "download_path": "../bin/lib/libc++.so"
+        }
+      }
+    },
+    "dexdump": {
+      "cloud_storage_bucket": "chromium-telemetry",
+      "cloud_storage_base_folder": "binary_dependencies",
+      "file_info": {
+        "android_host": {
+          "cloud_storage_hash": "38765b5b358c29003e56b1d214606ea13467b6fe",
+          "download_path": "../bin/dexdump"
+        }
+      }
+    },
+    "forwarder_device": {
+      "cloud_storage_bucket": "chromium-telemetry",
+      "cloud_storage_base_folder": "binary_dependencies",
+      "file_info": {
+        "android_armeabi-v7a": {
+          "cloud_storage_hash": "4858c9e41da72ad8ff24414731feae2137229361",
+          "download_path": "../bin/armeabi-v7a/forwarder_device"
+        },
+        "android_arm64-v8a": {
+          "cloud_storage_hash": "8cbd1ac2079ee82ce5f1cf4d3e85fc1e53a8f018",
+          "download_path": "../bin/arm64-v8a/forwarder_device"
+        }
+      }
+    },
+    "forwarder_host": {
+      "cloud_storage_bucket": "chromium-telemetry",
+      "cloud_storage_base_folder": "binary_dependencies",
+      "file_info": {
+        "android_host": {
+          "cloud_storage_hash": "b3dda9fbdd4a3fb933b64111c11070aa809c7ed4",
+          "download_path": "../bin/forwarder_host"
+        }
+      }
+    },
+    "md5sum_device": {
+      "cloud_storage_bucket": "chromium-telemetry",
+      "cloud_storage_base_folder": "binary_dependencies",
+      "file_info": {
+        "android_armeabi-v7a": {
+          "cloud_storage_hash": "c8894480be71d5e49118483d83ba7a6e0097cba6",
+          "download_path": "../bin/armeabi-v7a/md5sum_device"
+        },
+        "android_arm64-v8a": {
+          "cloud_storage_hash": "bbe410e2ffb48367ac4ca0874598d4f85fd16d9d",
+          "download_path": "../bin/arm64-v8a/md5sum_device"
+        },
+        "android_x86": {
+          "cloud_storage_hash": "b578a5c2c400ce39761e2558cdf2237567a57257",
+          "download_path": "../bin/x86/md5sum_device"
+        }
+      }
+    },
+    "md5sum_host": {
+      "cloud_storage_bucket": "chromium-telemetry",
+      "cloud_storage_base_folder": "binary_dependencies",
+      "file_info": {
+        "android_host": {
+          "cloud_storage_hash": "49e36c9c4246cfebef26cbd07436c1a8343254aa",
+          "download_path": "../bin/md5sum_host"
+        }
+      }
+    },
+    "pymock": {
+      "file_info": {
+        "android_host": {
+          "local_paths": [
+            "../../../tools/telemetry/third_party/mock"
+          ]
+        }
+      }
+    },
+    "split-select": {
+      "cloud_storage_bucket": "chromium-telemetry",
+      "cloud_storage_base_folder": "binary_dependencies",
+      "file_info": {
+        "android_host": {
+          "cloud_storage_hash": "3327881fa3951a503b9467425ea8e781cdffeb9f",
+          "download_path": "../bin/split-select"
+        }
+      }
+    }
+  }
+}
diff --git a/build/android/devil/devil_env.py b/build/android/devil/devil_env.py
new file mode 100644
index 0000000..fa7392f4
--- /dev/null
+++ b/build/android/devil/devil_env.py
@@ -0,0 +1,138 @@
+# 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.
+
+import contextlib
+import json
+import logging
+import os
+import sys
+import tempfile
+import threading
+
+# TODO(jbudorick): Update this once dependency_manager moves to catapult.
+CATAPULT_BASE_PATH = os.path.abspath(os.path.join(
+    os.path.dirname(__file__), os.pardir, os.pardir, os.pardir,
+    'tools', 'telemetry'))
+
+@contextlib.contextmanager
+def SysPath(path):
+  sys.path.append(path)
+  yield
+  if sys.path[-1] != path:
+    logging.debug('Expected %s at the end of sys.path. Full sys.path: %s',
+                  path, str(sys.path))
+    sys.path.remove(path)
+  else:
+    sys.path.pop()
+
+with SysPath(CATAPULT_BASE_PATH):
+  from catapult_base import dependency_manager # pylint: disable=import-error
+
+_ANDROID_BUILD_TOOLS = {'aapt', 'dexdump', 'split-select'}
+
+_DEVIL_DEFAULT_CONFIG = os.path.abspath(os.path.join(
+    os.path.dirname(__file__), 'devil_dependencies.json'))
+
+_LEGACY_ENVIRONMENT_VARIABLES = {
+  'ADB_PATH': {
+    'dependency_name': 'adb',
+    'platform': 'android_host',
+  },
+  'ANDROID_SDK_ROOT': {
+    'dependency_name': 'android_sdk',
+    'platform': 'android_host',
+  },
+}
+
+
+def _GetEnvironmentVariableConfig():
+  env_var_config = {}
+  for k, v in _LEGACY_ENVIRONMENT_VARIABLES.iteritems():
+    path = os.environ.get(k)
+    if path:
+      env_var_config[v['dependency_name']] = {
+        'file_info': {
+          v['platform']: {
+            'local_paths': [path]
+          }
+        }
+      }
+  return env_var_config
+
+
+class _Environment(object):
+
+  def __init__(self):
+    self._dm_init_lock = threading.Lock()
+    self._dm = None
+
+  def Initialize(self, configs=None, config_files=None):
+    """Initialize devil's environment from configuration files.
+
+    This uses all configurations provided via |configs| and |config_files|
+    to determine the locations of devil's dependencies. Configurations should
+    all take the form described by catapult_base.dependency_manager.BaseConfig.
+    If no configurations are provided, a default one will be used if available.
+
+    Args:
+      configs: An optional list of dict configurations.
+      config_files: An optional list of files to load
+    """
+
+    # Make sure we only initialize self._dm once.
+    with self._dm_init_lock:
+      if self._dm is None:
+        if configs is None:
+          configs = []
+
+        env_config = _GetEnvironmentVariableConfig()
+        if env_config:
+          configs.insert(0, env_config)
+        self._InitializeRecursive(
+            configs=configs,
+            config_files=config_files)
+        assert self._dm is not None, 'Failed to create dependency manager.'
+
+  def _InitializeRecursive(self, configs=None, config_files=None):
+    # This recurses through configs to create temporary files for each and
+    # take advantage of context managers to appropriately close those files.
+    # TODO(jbudorick): Remove this recursion if/when dependency_manager
+    # supports loading configurations directly from a dict.
+    if configs:
+      with tempfile.NamedTemporaryFile() as next_config_file:
+        next_config_file.write(json.dumps(configs[0]))
+        next_config_file.flush()
+        self._InitializeRecursive(
+            configs=configs[1:],
+            config_files=[next_config_file.name] + (config_files or []))
+    else:
+      config_files = config_files or []
+      if 'DEVIL_ENV_CONFIG' in os.environ:
+        config_files.append(os.environ.get('DEVIL_ENV_CONFIG'))
+      config_files.append(_DEVIL_DEFAULT_CONFIG)
+
+      self._dm = dependency_manager.DependencyManager(
+          [dependency_manager.BaseConfig(c) for c in config_files])
+
+  def FetchPath(self, dependency, arch=None, device=None):
+    if self._dm is None:
+      self.Initialize()
+    if dependency in _ANDROID_BUILD_TOOLS:
+      self.FetchPath('android_build_tools_libc++', arch=arch, device=device)
+    return self._dm.FetchPath(dependency, _GetPlatform(arch, device))
+
+  def LocalPath(self, dependency, arch=None, device=None):
+    if self._dm is None:
+      self.Initialize()
+    return self._dm.LocalPath(dependency, _GetPlatform(arch, device))
+
+
+def _GetPlatform(arch, device):
+  if not arch:
+    arch = device.product_cpu_abi if device else 'host'
+  return 'android_%s' % arch
+
+
+config = _Environment()
+
diff --git a/build/android/devil/utils/lazy/__init__.py b/build/android/devil/utils/lazy/__init__.py
new file mode 100644
index 0000000..3cc56c0a
--- /dev/null
+++ b/build/android/devil/utils/lazy/__init__.py
@@ -0,0 +1,5 @@
+# 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.
+
+from devil.utils.lazy.weak_constant import WeakConstant
diff --git a/build/android/devil/utils/lazy/weak_constant.py b/build/android/devil/utils/lazy/weak_constant.py
new file mode 100644
index 0000000..3558f29
--- /dev/null
+++ b/build/android/devil/utils/lazy/weak_constant.py
@@ -0,0 +1,29 @@
+# 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.
+
+import threading
+
+
+class WeakConstant(object):
+  """A thread-safe, lazily initialized object.
+
+  This does not support modification after initialization. The intended
+  constant nature of the object is not enforced, though, hence the "weak".
+  """
+
+  def __init__(self, initializer):
+    self._initialized = False
+    self._initializer = initializer
+    self._lock = threading.Lock()
+    self._val = None
+
+  def read(self):
+    """Get the object, creating it if necessary."""
+    if self._initialized:
+      return self._val
+    with self._lock:
+      if not self._initialized:
+        self._val = self._initializer()
+        self._initialized = True
+    return self._val
diff --git a/build/android/devil/utils/lsusb.py b/build/android/devil/utils/lsusb.py
index 9c98fa6..d322e5c 100644
--- a/build/android/devil/utils/lsusb.py
+++ b/build/android/devil/utils/lsusb.py
@@ -5,7 +5,7 @@
 import logging
 import re
 
-from pylib import cmd_helper
+from devil.utils import cmd_helper
 
 _INDENTATION_RE = re.compile(r'^( *)')
 _LSUSB_BUS_DEVICE_RE = re.compile(r'^Bus (\d{3}) Device (\d{3}):')
diff --git a/build/android/devil/utils/mock_calls.py b/build/android/devil/utils/mock_calls.py
index 59167bac..bc3b54a0 100644
--- a/build/android/devil/utils/mock_calls.py
+++ b/build/android/devil/utils/mock_calls.py
@@ -6,14 +6,12 @@
 A test facility to assert call sequences while mocking their behavior.
 """
 
-import os
 import sys
 import unittest
 
-from pylib import constants
+from devil import devil_env
 
-sys.path.append(os.path.join(
-    constants.DIR_SOURCE_ROOT, 'third_party', 'pymock'))
+sys.path.append(devil_env.config.LocalPath('pymock'))
 import mock # pylint: disable=F0401
 
 
diff --git a/build/android/devil/utils/mock_calls_test.py b/build/android/devil/utils/mock_calls_test.py
index ae2acbb8..290c184b 100755
--- a/build/android/devil/utils/mock_calls_test.py
+++ b/build/android/devil/utils/mock_calls_test.py
@@ -12,12 +12,11 @@
 import sys
 import unittest
 
+from devil import devil_env
 from devil.android.sdk import version_codes
 from devil.utils import mock_calls
-from pylib import constants
 
-sys.path.append(os.path.join(
-    constants.DIR_SOURCE_ROOT, 'third_party', 'pymock'))
+sys.path.append(devil_env.config.LocalPath('pymock'))
 import mock # pylint: disable=F0401
 
 
diff --git a/build/android/devil_chromium.json b/build/android/devil_chromium.json
new file mode 100644
index 0000000..99aabad
--- /dev/null
+++ b/build/android/devil_chromium.json
@@ -0,0 +1,59 @@
+{
+  "config_type": "BaseConfig",
+  "dependencies": {
+    "aapt": {
+      "file_info": {
+        "android_host": {
+          "local_paths": [
+            "../../third_party/android_tools/sdk/build-tools/23.0.0/aapt"
+          ]
+        }
+      }
+    },
+    "adb": {
+      "file_info": {
+        "android_host": {
+          "local_paths": [
+            "../../third_party/android_tools/sdk/platform-tools/adb"
+          ]
+        }
+      }
+    },
+    "android_sdk": {
+      "file_info": {
+        "android_host": {
+          "local_paths": [
+            "../../third_party/android_tools/sdk"
+          ]
+        }
+      }
+    },
+    "dexdump": {
+      "file_info": {
+        "android_host": {
+          "local_paths": [
+            "../../third_party/android_tools/sdk/build-tools/23.0.0/dexdump"
+          ]
+        }
+      }
+    },
+    "split-select": {
+      "file_info": {
+        "android_host": {
+          "local_paths": [
+            "../../third_party/android_tools/sdk/build-tools/23.0.0/split-select"
+          ]
+        }
+      }
+    },
+    "pymock": {
+      "file_info": {
+        "android_host": {
+          "local_paths": [
+            "../../third_party/pymock"
+          ]
+        }
+      }
+    }
+  }
+}
diff --git a/build/android/devil_chromium.py b/build/android/devil_chromium.py
new file mode 100644
index 0000000..d626af6
--- /dev/null
+++ b/build/android/devil_chromium.py
@@ -0,0 +1,90 @@
+# 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.
+
+"""Configures devil for use in chromium."""
+
+import os
+
+from devil import devil_env
+
+
+_DEVIL_CONFIG = os.path.abspath(
+    os.path.join(os.path.dirname(__file__), 'devil_chromium.json'))
+
+_DEVIL_BUILD_PRODUCT_DEPS = {
+  'forwarder_device': {
+    'armeabi-v7a': 'forwarder_dist',
+    'arm64-v8a': 'forwarder_dist',
+    'x86': 'forwarder_dist',
+  },
+  'forwarder_host': {
+    'any': 'host_forwarder',
+  },
+  'md5sum_device': {
+    'armeabi-v7a': 'md5sum_dist',
+    'arm64-v8a': 'md5sum_dist',
+    'x86': 'md5sum_dist',
+  },
+  'md5sum_host': {
+    'any': 'md5sum_bin_host',
+  },
+}
+
+
+def Initialize(output_directory=None, custom_deps=None):
+  """Initializes devil with chromium's binaries and third-party libraries.
+
+  This includes:
+    - Libraries:
+      - the android SDK ("android_sdk")
+      - pymock ("pymock")
+    - Build products:
+      - host & device forwarder binaries
+          ("forwarder_device" and "forwarder_host")
+      - host & device md5sum binaries ("md5sum_device" and "md5sum_host")
+
+  Args:
+    output_directory: An optional path to the output directory. If not set,
+      no built dependencies are configured.
+    custom_deps: An optional dictionary specifying custom dependencies.
+      This should be of the form:
+
+        {
+          'dependency_name': {
+            'platform': 'path',
+            ...
+          },
+          ...
+        }
+  """
+
+  devil_dynamic_deps = {}
+
+  if output_directory:
+    for dep_name, arch_dict in _DEVIL_BUILD_PRODUCT_DEPS.iteritems():
+      devil_dynamic_deps[dep_name] = {}
+      for arch, name in arch_dict.iteritems():
+        devil_dynamic_deps[dep_name][arch] = os.path.join(
+            output_directory, name)
+
+  devil_dynamic_config = {
+    'config_type': 'BaseConfig',
+    'dependencies': {
+      dep_name: {
+        'file_info': {
+          'android_%s' % arch: {
+            'local_paths': [path]
+          }
+          for arch, path in arch_dict.iteritems()
+        }
+      }
+      for dep_name, arch_dict in devil_dynamic_deps.iteritems()
+    }
+  }
+  if custom_deps:
+    devil_dynamic_config['dependencies'].update(custom_deps)
+
+  devil_env.config.Initialize(
+      configs=[devil_dynamic_config], config_files=[_DEVIL_CONFIG])
+
diff --git a/build/android/gyp/apk_install.py b/build/android/gyp/apk_install.py
index 33697ca..9c907638 100755
--- a/build/android/gyp/apk_install.py
+++ b/build/android/gyp/apk_install.py
@@ -17,9 +17,11 @@
 from util import build_utils
 from util import md5_check
 
-BUILD_ANDROID_DIR = os.path.join(os.path.dirname(__file__), '..')
+BUILD_ANDROID_DIR = os.path.abspath(
+    os.path.join(os.path.dirname(__file__), '..'))
 sys.path.append(BUILD_ANDROID_DIR)
 
+import devil_chromium
 from devil.android import apk_helper
 from pylib import constants
 
@@ -74,15 +76,20 @@
       help='Path to touch on success.')
   parser.add_option('--configuration-name',
       help='The build CONFIGURATION_NAME')
+  parser.add_option('--output-directory',
+      help='The output directory.')
   options, _ = parser.parse_args()
 
+  constants.SetBuildType(options.configuration_name)
+
+  devil_chromium.Initialize(
+      output_directory=os.path.abspath(options.output_directory))
+
   device = build_device.GetBuildDeviceFromPath(
       options.build_device_configuration)
   if not device:
     return
 
-  constants.SetBuildType(options.configuration_name)
-
   serial_number = device.GetSerialNumber()
   apk_package = apk_helper.GetPackageName(options.apk_path)
 
diff --git a/build/android/gyp/create_device_library_links.py b/build/android/gyp/create_device_library_links.py
index 8c155a0..6b0b24d7 100755
--- a/build/android/gyp/create_device_library_links.py
+++ b/build/android/gyp/create_device_library_links.py
@@ -18,9 +18,11 @@
 from util import build_device
 from util import build_utils
 
-BUILD_ANDROID_DIR = os.path.join(os.path.dirname(__file__), '..')
+BUILD_ANDROID_DIR = os.path.abspath(
+    os.path.join(os.path.dirname(__file__), '..'))
 sys.path.append(BUILD_ANDROID_DIR)
 
+import devil_chromium
 from devil.android import apk_helper
 from pylib import constants
 
@@ -96,6 +98,8 @@
       help='Path to build device configuration.')
   parser.add_option('--configuration-name',
       help='The build CONFIGURATION_NAME')
+  parser.add_option('--output-directory',
+      help='The output directory')
   options, _ = parser.parse_args(args)
 
   required_options = ['apk', 'libraries', 'script_host_path',
@@ -103,6 +107,9 @@
   build_utils.CheckOptions(options, parser, required=required_options)
   constants.SetBuildType(options.configuration_name)
 
+  devil_chromium.Initialize(
+      output_directory=os.path.abspath(options.output_directory))
+
   CreateSymlinkScript(options)
   TriggerSymlinkScript(options)
 
diff --git a/build/android/gyp/get_device_configuration.py b/build/android/gyp/get_device_configuration.py
index 390eb2f..0ec08ef9 100755
--- a/build/android/gyp/get_device_configuration.py
+++ b/build/android/gyp/get_device_configuration.py
@@ -11,18 +11,29 @@
 """
 
 import optparse
+import os
 import sys
 
-from util import build_utils
 from util import build_device
+from util import build_utils
+
+BUILD_ANDROID_DIR = os.path.abspath(
+    os.path.join(os.path.dirname(__file__), '..'))
+sys.path.append(BUILD_ANDROID_DIR)
+
+import devil_chromium
 
 
 def main(argv):
   parser = optparse.OptionParser()
   parser.add_option('--stamp', action='store')
   parser.add_option('--output', action='store')
+  parser.add_option('--output-directory', action='store')
   options, _ = parser.parse_args(argv)
 
+  devil_chromium.Initialize(
+      output_directory=os.path.abspath(options.output_directory))
+
   devices = build_device.GetAttachedDevices()
 
   device_configurations = []
diff --git a/build/android/gyp/push_libraries.py b/build/android/gyp/push_libraries.py
index 6b31a2e..452b873b 100755
--- a/build/android/gyp/push_libraries.py
+++ b/build/android/gyp/push_libraries.py
@@ -12,7 +12,8 @@
 import os
 import sys
 
-BUILD_ANDROID_DIR = os.path.join(os.path.dirname(__file__), os.pardir)
+BUILD_ANDROID_DIR = os.path.abspath(
+    os.path.join(os.path.dirname(__file__), os.pardir))
 sys.path.append(BUILD_ANDROID_DIR)
 
 from pylib import constants
diff --git a/build/android/gyp/util/build_device.py b/build/android/gyp/util/build_device.py
index a19045be..34484ac 100644
--- a/build/android/gyp/util/build_device.py
+++ b/build/android/gyp/util/build_device.py
@@ -13,7 +13,8 @@
 
 from util import build_utils
 
-BUILD_ANDROID_DIR = os.path.join(os.path.dirname(__file__), '..', '..')
+BUILD_ANDROID_DIR = os.path.abspath(
+    os.path.join(os.path.dirname(__file__), '..', '..'))
 sys.path.append(BUILD_ANDROID_DIR)
 
 from devil.android import device_errors
diff --git a/build/android/gyp/write_build_config.py b/build/android/gyp/write_build_config.py
index b8b8ec8..629ce73 100755
--- a/build/android/gyp/write_build_config.py
+++ b/build/android/gyp/write_build_config.py
@@ -37,6 +37,13 @@
 
 import write_ordered_libraries
 
+
+# Types that should never be used as a dependency of another build config.
+_ROOT_TYPES = ('android_apk', 'deps_dex', 'java_binary', 'resource_rewriter')
+# Types that should not allow code deps to pass through.
+_RESOURCE_TYPES = ('android_assets', 'android_resources')
+
+
 class AndroidManifest(object):
   def __init__(self, path):
     self.path = path
@@ -143,6 +150,16 @@
   return create_list(compressed), create_list(uncompressed)
 
 
+def _FilterUnwantedDepsPaths(dep_paths, target_type):
+  # Don't allow root targets to be considered as a dep.
+  ret = [p for p in dep_paths if GetDepConfig(p)['type'] not in _ROOT_TYPES]
+
+  # Don't allow java libraries to cross through assets/resources.
+  if target_type in _RESOURCE_TYPES:
+    ret = [p for p in ret if GetDepConfig(p)['type'] in _RESOURCE_TYPES]
+  return ret
+
+
 def main(argv):
   parser = optparse.OptionParser()
   build_utils.AddDepfileOption(parser)
@@ -206,6 +223,7 @@
     parser.error('No positional arguments should be given.')
 
   required_options_map = {
+      'java_binary': ['build_config', 'jar_path'],
       'java_library': ['build_config', 'jar_path'],
       'android_assets': ['build_config'],
       'android_resources': ['build_config', 'resources_zip'],
@@ -242,8 +260,11 @@
 
   direct_deps_config_paths = [
       c for c in possible_deps_config_paths if not c in unknown_deps]
+  direct_deps_config_paths = _FilterUnwantedDepsPaths(direct_deps_config_paths,
+                                                      options.type)
 
   deps = Deps(direct_deps_config_paths)
+
   direct_library_deps = deps.Direct('java_library')
   all_library_deps = deps.All('java_library')
 
@@ -265,12 +286,13 @@
       'name': os.path.basename(options.build_config),
       'path': options.build_config,
       'type': options.type,
-      'deps_configs': direct_deps_config_paths,
+      'deps_configs': direct_deps_config_paths
     }
   }
   deps_info = config['deps_info']
 
-  if options.type == 'java_library' and not options.bypass_platform_checks:
+  if (options.type in ('java_binary', 'java_library') and
+      not options.bypass_platform_checks):
     deps_info['requires_android'] = options.requires_android
     deps_info['supports_android'] = options.supports_android
 
@@ -287,7 +309,7 @@
       raise Exception('Not all deps support the Android platform: ' +
           str(deps_not_support_android))
 
-  if options.type in ['java_library', 'android_apk']:
+  if options.type in ('java_binary', 'java_library', 'android_apk'):
     javac_classpath = [c['jar_path'] for c in direct_library_deps]
     java_full_classpath = [c['jar_path'] for c in all_library_deps]
     deps_info['resources_deps'] = [c['path'] for c in all_resources_deps]
@@ -303,7 +325,7 @@
       'full_classpath': java_full_classpath
     }
 
-  if options.type == 'java_library':
+  if options.type in ('java_binary', 'java_library'):
     # Only resources might have srcjars (normal srcjar targets are listed in
     # srcjar_deps). A resource's srcjar contains the R.java file for those
     # resources, and (like Android's default build system) we allow a library to
diff --git a/build/android/incremental_install/installer.py b/build/android/incremental_install/installer.py
index 373889df..15bdbeeb 100755
--- a/build/android/incremental_install/installer.py
+++ b/build/android/incremental_install/installer.py
@@ -14,7 +14,9 @@
 import shutil
 import sys
 
-sys.path.append(os.path.join(os.path.dirname(__file__), os.pardir))
+sys.path.append(
+    os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir)))
+import devil_chromium
 from devil.android import apk_helper
 from devil.android import device_utils
 from devil.android import device_errors
@@ -253,6 +255,8 @@
   if args.output_directory:
     constants.SetOutputDirectory(args.output_directory)
 
+  devil_chromium.Initialize(output_directory=constants.GetOutDirectory())
+
   if args.device:
     # Retries are annoying when commands fail for legitimate reasons. Might want
     # to enable them if this is ever used on bots though.
diff --git a/build/android/provision_devices.py b/build/android/provision_devices.py
index 3a2e100..caa9e23f6 100755
--- a/build/android/provision_devices.py
+++ b/build/android/provision_devices.py
@@ -21,6 +21,7 @@
 import sys
 import time
 
+import devil_chromium
 from devil.android import battery_utils
 from devil.android import device_blacklist
 from devil.android import device_errors
@@ -103,7 +104,8 @@
 
   try:
     if should_run_phase(_PHASES.WIPE):
-      if options.chrome_specific_wipe:
+      if (options.chrome_specific_wipe or device.build_version_sdk >=
+          version_codes.MARSHMALLOW):
         run_phase(WipeChromeData)
       else:
         run_phase(WipeDevice)
@@ -490,6 +492,8 @@
 
   run_tests_helper.SetLogLevel(args.verbose)
 
+  devil_chromium.Initialize()
+
   return ProvisionDevices(args)
 
 
diff --git a/build/android/pylib/constants/__init__.py b/build/android/pylib/constants/__init__.py
index 772af93..1a48723d 100644
--- a/build/android/pylib/constants/__init__.py
+++ b/build/android/pylib/constants/__init__.py
@@ -17,6 +17,7 @@
 from devil.android.sdk import version_codes
 from devil.constants import exit_codes
 
+
 keyevent = devil.android.sdk.keyevent
 
 
@@ -243,43 +244,13 @@
       GetBuildType() if build_type is None else build_type))
 
 
-def _Memoize(func):
-  def Wrapper():
-    try:
-      return func._result
-    except AttributeError:
-      func._result = func()
-      return func._result
-  return Wrapper
-
-
-def SetAdbPath(adb_path):
-  os.environ['ADB_PATH'] = adb_path
-
-
+# TODO(jbudorick): Convert existing callers to AdbWrapper.GetAdbPath() and
+# remove this.
 def GetAdbPath():
-  # Check if a custom adb path as been set. If not, try to find adb
-  # on the system.
-  if os.environ.get('ADB_PATH'):
-    return os.environ.get('ADB_PATH')
-  else:
-    return _FindAdbPath()
+  from devil.android.sdk import adb_wrapper
+  return adb_wrapper.AdbWrapper.GetAdbPath()
 
 
-@_Memoize
-def _FindAdbPath():
-  if os.environ.get('ANDROID_SDK_ROOT'):
-    return 'adb'
-  # If envsetup.sh hasn't been sourced and there's no adb in the path,
-  # set it here.
-  try:
-    with file(os.devnull, 'w') as devnull:
-      subprocess.call(['adb', 'version'], stdout=devnull, stderr=devnull)
-    return 'adb'
-  except OSError:
-    logging.debug('No adb found in $PATH, fallback to checked in binary.')
-    return os.path.join(ANDROID_SDK_ROOT, 'platform-tools', 'adb')
-
 # Exit codes
 ERROR_EXIT_CODE = exit_codes.ERROR
 INFRA_EXIT_CODE = exit_codes.INFRA
diff --git a/build/android/pylib/forwarder.py b/build/android/pylib/forwarder.py
index 36226d1..b8952cc 100644
--- a/build/android/pylib/forwarder.py
+++ b/build/android/pylib/forwarder.py
@@ -9,6 +9,7 @@
 import os
 import psutil
 
+from devil import devil_env
 from devil.android.valgrind_tools import base_tool
 from devil.utils import cmd_helper
 from pylib import constants
@@ -77,7 +78,7 @@
 
       device_serial = str(device)
       redirection_commands = [
-          ['--adb=' + constants.GetAdbPath(),
+          ['--adb=' + devil_env.config.FetchPath('adb'),
            '--serial-id=' + device_serial,
            '--map', str(device_port), str(host_port)]
           for device_port, host_port in port_pairs]
@@ -197,11 +198,8 @@
     self._initialized_devices = set()
     self._device_to_host_port_map = dict()
     self._host_to_device_port_map = dict()
-    self._host_forwarder_path = os.path.join(
-        constants.GetOutDirectory(), 'host_forwarder')
+    self._host_forwarder_path = devil_env.config.FetchPath('forwarder_host')
     assert os.path.exists(self._host_forwarder_path), 'Please build forwarder2'
-    self._device_forwarder_path_on_host = os.path.join(
-        constants.GetOutDirectory(), 'forwarder_dist')
     self._InitHostLocked()
 
   @staticmethod
@@ -216,7 +214,7 @@
     if not serial_with_port in instance._device_to_host_port_map:
       logging.error('Trying to unmap non-forwarded port %d', device_port)
       return
-    redirection_command = ['--adb=' + constants.GetAdbPath(),
+    redirection_command = ['--adb=' + devil_env.config.FetchPath('adb'),
                            '--serial-id=' + serial,
                            '--unmap', str(device_port)]
     logging.info('Undo forwarding using command: %s', redirection_command)
@@ -279,9 +277,16 @@
     if device_serial in self._initialized_devices:
       return
     Forwarder._KillDeviceLocked(device, tool)
+    forwarder_device_path_on_host = devil_env.config.FetchPath(
+        'forwarder_device', device=device)
+    forwarder_device_path_on_device = (
+        Forwarder._DEVICE_FORWARDER_FOLDER
+        if os.path.isdir(forwarder_device_path_on_host)
+        else Forwarder._DEVICE_FORWARDER_PATH)
     device.PushChangedFiles([(
-        self._device_forwarder_path_on_host,
-        Forwarder._DEVICE_FORWARDER_FOLDER)])
+        forwarder_device_path_on_host,
+        forwarder_device_path_on_device)])
+
     cmd = '%s %s' % (tool.GetUtilWrapper(), Forwarder._DEVICE_FORWARDER_PATH)
     device.RunShellCommand(
         cmd, env={'LD_LIBRARY_PATH': Forwarder._DEVICE_FORWARDER_FOLDER},
diff --git a/build/android/pylib/gtest/filter/content_browsertests_disabled b/build/android/pylib/gtest/filter/content_browsertests_disabled
index b9dd105b..abe4066 100644
--- a/build/android/pylib/gtest/filter/content_browsertests_disabled
+++ b/build/android/pylib/gtest/filter/content_browsertests_disabled
@@ -36,17 +36,6 @@
 RendererAccessibilityTest.ShowAccessibilityObject
 RendererAccessibilityTest.TextSelectionShouldSendRoot
 
-# http://crbug.com/215894
-DownloadContentTest.CancelInterruptedDownload
-DownloadContentTest.CancelResumingDownload
-DownloadContentTest.RemoveDownload
-DownloadContentTest.RemoveResumingDownload
-DownloadContentTest.ResumeInterruptedDownload
-DownloadContentTest.ResumeInterruptedDownloadNoRange
-DownloadContentTest.ResumeInterruptedDownloadNoVerifiers
-DownloadContentTest.ResumeInterruptedDownloadBadPrecondition
-DownloadContentTest.ResumeWithDeletedFile
-
 # http://crbug.com/386227
 IndexedDBBrowserTest.VersionChangeCrashResilience
 
diff --git a/build/android/pylib/perf/test_runner.py b/build/android/pylib/perf/test_runner.py
index a580fd4..161c511 100644
--- a/build/android/pylib/perf/test_runner.py
+++ b/build/android/pylib/perf/test_runner.py
@@ -74,6 +74,7 @@
 
 
 def _GetChromiumRevision():
+  # pylint: disable=line-too-long
   """Get the git hash and commit position of the chromium master branch.
 
   See: https://chromium.googlesource.com/chromium/tools/build/+/master/scripts/slave/runtest.py#212
@@ -81,6 +82,7 @@
   Returns:
     A dictionary with 'revision' and 'commit_pos' keys.
   """
+  # pylint: enable=line-too-long
   status, output = cmd_helper.GetCmdStatusAndOutput(
       ['git', 'log', '-n', '1', '--pretty=format:%H%n%B', 'HEAD'],
       constants.DIR_SOURCE_ROOT)
diff --git a/build/android/pylintrc b/build/android/pylintrc
index 9c2ab5a..8005a5d 100644
--- a/build/android/pylintrc
+++ b/build/android/pylintrc
@@ -1,3 +1,7 @@
+[FORMAT]
+
+max-line-length=80
+
 [MESSAGES CONTROL]
 
 disable=abstract-class-not-used,bad-continuation,bad-indentation,duplicate-code,fixme,invalid-name,locally-disabled,locally-enabled,missing-docstring,star-args,too-few-public-methods,too-many-arguments,too-many-branches,too-many-instance-attributes,too-many-lines,too-many-locals,too-many-public-methods,too-many-statements,
diff --git a/build/android/setup.gyp b/build/android/setup.gyp
index 419ed985..0ef0531 100644
--- a/build/android/setup.gyp
+++ b/build/android/setup.gyp
@@ -42,6 +42,7 @@
           'action': [
             'python', 'gyp/get_device_configuration.py',
             '--output=<(build_device_config_path)',
+            '--output-directory=<(PRODUCT_DIR)',
           ],
         }
       ],
diff --git a/build/android/test_runner.py b/build/android/test_runner.py
index 90210b6..9f1b22e 100755
--- a/build/android/test_runner.py
+++ b/build/android/test_runner.py
@@ -16,6 +16,8 @@
 import threading
 import unittest
 
+import devil_chromium
+
 from devil import base_error
 from devil.android import apk_helper
 from devil.android import device_blacklist
@@ -47,6 +49,10 @@
 from pylib.results import report_results
 
 
+_DEVIL_STATIC_CONFIG_FILE = os.path.abspath(os.path.join(
+    constants.DIR_SOURCE_ROOT, 'build', 'android', 'devil_config.json'))
+
+
 def AddCommonOptions(parser):
   """Adds all common options to |parser|."""
 
@@ -111,8 +117,19 @@
     constants.SetBuildDirectory(args.build_directory)
   if args.output_directory:
     constants.SetOutputDirectory(args.output_directory)
+
+  devil_custom_deps = None
   if args.adb_path:
-    constants.SetAdbPath(args.adb_path)
+    devil_custom_deps = {
+      'adb': {
+        'android_host': [args.adb_path]
+      }
+    }
+
+  devil_chromium.Initialize(
+      output_directory=constants.GetOutDirectory(),
+      custom_deps=devil_custom_deps)
+
   # Some things such as Forwarder require ADB to be in the environment path.
   adb_dir = os.path.dirname(constants.GetAdbPath())
   if adb_dir and adb_dir not in os.environ['PATH'].split(os.pathsep):
diff --git a/build/android/tombstones.py b/build/android/tombstones.py
index f1108dd36..ccb86a4 100755
--- a/build/android/tombstones.py
+++ b/build/android/tombstones.py
@@ -18,6 +18,8 @@
 import sys
 import optparse
 
+import devil_chromium
+
 from devil.android import device_blacklist
 from devil.android import device_errors
 from devil.android import device_utils
@@ -241,6 +243,8 @@
                if options.blacklist_file
                else None)
 
+  devil_chromium.Initialize()
+
   if options.device:
     devices = [device_utils.DeviceUtils(options.device)]
   else:
diff --git a/build/args/aura_android.gni b/build/args/aura_android.gni
index 725c41b..fc67e649 100644
--- a/build/args/aura_android.gni
+++ b/build/args/aura_android.gni
@@ -15,4 +15,5 @@
 
 # ui.gni overrides
 use_aura = true
+android_java_ui = false
 toolkit_views = true
diff --git a/build/buildflag_header.gypi b/build/buildflag_header.gypi
index af86677..83b505a 100644
--- a/build/buildflag_header.gypi
+++ b/build/buildflag_header.gypi
@@ -115,4 +115,9 @@
       ],
     }
   ],
+
+  # Allow the file to be included based on the given buildflag_header_path.
+  'direct_dependent_settings': {
+    'include_dirs': [ '<(SHARED_INTERMEDIATE_DIR)' ],
+  },
 }
diff --git a/build/common.gypi b/build/common.gypi
index 0974b49..fe6722e 100644
--- a/build/common.gypi
+++ b/build/common.gypi
@@ -756,7 +756,7 @@
         }],
 
         # Flags to use Wayland server support.
-        ['chromeos==1', {
+        ['chromeos==1 and use_ozone==1', {
           'enable_wayland_server%': 1,
         }, {
           'enable_wayland_server%': 0,
@@ -1492,7 +1492,7 @@
     'sas_dll_exists': '<!pymod_do_main(dir_exists "<(sas_dll_path)")',
     'wix_exists': '<!pymod_do_main(dir_exists "<(wix_path)")',
 
-    'windows_sdk_path%': 'C:/Program Files (x86)/Windows Kits/8.1',
+    'windows_sdk_path%': 'C:/Program Files (x86)/Windows Kits/10',
     'directx_sdk_default_path': '<(DEPTH)/third_party/directxsdk/files',
 
     # Whether we are using the rlz library or not.  Platforms like Android send
@@ -1896,6 +1896,9 @@
       ['OS=="mac" or OS=="ios"', {
         'clang%': 1,
 
+        # On Mac and iOS we just use the default system allocator.
+        'use_allocator%': 'none',
+
         'variables': {
           # Mac OS X SDK and deployment target support.  The SDK identifies
           # the version of the system headers that will be used, and
@@ -2886,9 +2889,9 @@
           '__STD_C',
           '_CRT_SECURE_NO_DEPRECATE',
           '_SCL_SECURE_NO_DEPRECATE',
-          # This define is required to pull in the new Win8 interfaces from
+          # This define is required to pull in the new Win 10 interfaces from
           # system headers like ShObjIdl.h.
-          'NTDDI_VERSION=0x06030000',
+          'NTDDI_VERSION=0x0A000000',
           # This is required for ATL to use XP-safe versions of its functions.
           '_USING_V110_SDK71_',
         ],
@@ -3337,17 +3340,17 @@
             'MinimumRequiredVersion': '5.02',  # Server 2003.
             'TargetMachine': '17', # x86 - 64
             'AdditionalLibraryDirectories!':
-              ['<(windows_sdk_path)/Lib/win8/um/x86'],
+              ['<(windows_sdk_path)/Lib/10.0.10240.0/um/x86'],
             'AdditionalLibraryDirectories':
-              ['<(windows_sdk_path)/Lib/win8/um/x64'],
+              ['<(windows_sdk_path)/Lib/10.0.10240.0/um/x64'],
             # Doesn't exist x64 SDK. Should use oleaut32 in any case.
             'IgnoreDefaultLibraryNames': [ 'olepro32.lib' ],
           },
           'VCLibrarianTool': {
             'AdditionalLibraryDirectories!':
-              ['<(windows_sdk_path)/Lib/win8/um/x86'],
+              ['<(windows_sdk_path)/Lib/10.0.10240.0/um/x86'],
             'AdditionalLibraryDirectories':
-              ['<(windows_sdk_path)/Lib/win8/um/x64'],
+              ['<(windows_sdk_path)/Lib/10.0.10240.0/um/x64'],
             'TargetMachine': '17', # x64
           },
         },
@@ -4955,20 +4958,14 @@
             ],
             'target_conditions': [
               ['_type=="executable"', {
-                # Force android tools to export the "main" symbol so they can be
-                # loaded on ICS using the run_pie wrapper. See crbug.com/373219.
-                # TODO(primiano): remove -fvisibility and -rdynamic flags below
-                # when ICS support will be dropped.
                 'cflags': [
                   '-fPIE',
-                  '-fvisibility=default',
                 ],
                 'ldflags': [
                   '-Bdynamic',
                   '-Wl,--gc-sections',
                   '-Wl,-z,nocopyreloc',
                   '-pie',
-                  '-rdynamic',
                   # crtbegin_dynamic.o should be the last item in ldflags.
                   '<(android_ndk_lib)/crtbegin_dynamic.o',
                 ],
@@ -5529,8 +5526,8 @@
     ['OS=="win"', {
       'target_defaults': {
         'defines': [
-          '_WIN32_WINNT=0x0603',
-          'WINVER=0x0603',
+          '_WIN32_WINNT=0x0A00',
+          'WINVER=0x0A00',
           'WIN32',
           '_WINDOWS',
           'NOMINMAX',
@@ -5640,9 +5637,9 @@
           }],
         ],
         'msvs_system_include_dirs': [
-          '<(windows_sdk_path)/Include/shared',
-          '<(windows_sdk_path)/Include/um',
-          '<(windows_sdk_path)/Include/winrt',
+          '<(windows_sdk_path)/Include/10.0.10240.0/shared',
+          '<(windows_sdk_path)/Include/10.0.10240.0/um',
+          '<(windows_sdk_path)/Include/10.0.10240.0/winrt',
           '$(VSInstallDir)/VC/atlmfc/include',
         ],
         'msvs_cygwin_shell': 0,
diff --git a/build/config/android/internal_rules.gni b/build/config/android/internal_rules.gni
index 4f1e491..3727e8d 100644
--- a/build/config/android/internal_rules.gni
+++ b/build/config/android/internal_rules.gni
@@ -341,7 +341,8 @@
 
     assert(type == "android_apk" || type == "java_library" ||
            type == "android_resources" || type == "deps_dex" ||
-           type == "android_assets" || type == "resource_rewriter")
+           type == "android_assets" || type == "resource_rewriter" ||
+           type == "java_binary")
 
     deps = []
     forward_variables_from(invoker,
@@ -379,7 +380,7 @@
       rebase_path(build_config, root_build_dir),
     ]
 
-    is_java_library = type == "java_library"
+    is_java = type == "java_library" || type == "java_binary"
     is_apk = type == "android_apk"
     is_android_assets = type == "android_assets"
     is_android_resources = type == "android_resources"
@@ -387,30 +388,30 @@
 
     supports_android =
         is_apk || is_android_assets || is_android_resources || is_deps_dex ||
-        (is_java_library && defined(invoker.supports_android) &&
+        (is_java && defined(invoker.supports_android) &&
          invoker.supports_android)
     requires_android =
         is_apk || is_android_assets || is_android_resources || is_deps_dex ||
-        (is_java_library && defined(invoker.requires_android) &&
+        (is_java && defined(invoker.requires_android) &&
          invoker.requires_android)
 
     assert(!requires_android || supports_android,
            "requires_android requires" + " supports_android")
 
     # Mark these variables as used.
-    assert(is_java_library || true)
+    assert(is_java || true)
     assert(is_apk || true)
     assert(is_android_resources || true)
     assert(is_deps_dex || true)
 
-    if (is_java_library || is_apk) {
+    if (is_java || is_apk) {
       args += [
         "--jar-path",
         rebase_path(invoker.jar_path, root_build_dir),
       ]
     }
 
-    if (is_apk || is_deps_dex || (is_java_library && supports_android)) {
+    if (is_apk || is_deps_dex || (is_java && supports_android)) {
       args += [
         "--dex-path",
         rebase_path(invoker.dex_path, root_build_dir),
@@ -1547,7 +1548,11 @@
 
     write_build_config(build_config_target_name) {
       forward_variables_from(invoker, [ "deps" ])
-      type = "java_library"
+      if (defined(invoker.is_java_binary) && invoker.is_java_binary) {
+        type = "java_binary"
+      } else {
+        type = "java_library"
+      }
       supports_android = _supports_android
       requires_android = _requires_android
       bypass_platform_checks = defined(invoker.bypass_platform_checks) &&
diff --git a/build/config/android/rules.gni b/build/config/android/rules.gni
index f4219f23..e8b6572 100644
--- a/build/config/android/rules.gni
+++ b/build/config/android/rules.gni
@@ -889,12 +889,11 @@
 template("java_binary") {
   set_sources_assignment_filter([])
 
-  # TODO(cjhopman): This should not act like a java_library for dependents (i.e.
-  # dependents shouldn't get the jar in their classpath, etc.).
   java_library_impl(target_name) {
     forward_variables_from(invoker, "*")
     supports_android = false
     main_class = invoker.main_class
+    is_java_binary = true
   }
 }
 
diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn
index b26f033..49b3737f 100644
--- a/build/config/compiler/BUILD.gn
+++ b/build/config/compiler/BUILD.gn
@@ -39,10 +39,6 @@
   binutils_path = rebase_path("//third_party/binutils/Linux_x64/Release/bin",
                               root_build_dir)
 
-  # Compile in such a way as to enable profiling of the generated code. For
-  # example, don't omit the frame pointer and leave in symbols.
-  enable_profiling = false
-
   # Compile in such a way as to make it possible for the profiler to unwind full
   # stack frames. Setting this flag has a large effect on the performance of the
   # generated code than just setting profiling, but gives the profiler more
@@ -209,11 +205,6 @@
   # -----------------------------------
   if (is_posix && !(is_mac || is_ios)) {
     if (enable_profiling && !is_debug) {
-      # The GYP build spams this define into every compilation unit, as we do
-      # here, but it only appears to be used in base and a couple other places.
-      # TODO(abarth): Should we move this define closer to where it's used?
-      defines += [ "ENABLE_PROFILING" ]
-
       cflags += [
         "-fno-omit-frame-pointer",
         "-g",
@@ -557,11 +548,12 @@
           "-arch",
           "arm-nonsfi",
           "--pnacl-bias=arm-nonsfi",
-          "--target=arm-unknown-nacl",
+          "--target=armv7-unknown-nacl-gnueabihf",
         ]
         ldflags += [
           "-arch",
           "arm-nonsfi",
+          "--target=armv7-unknown-nacl-gnueabihf",
         ]
       }
     }
diff --git a/build/config/compiler/compiler.gni b/build/config/compiler/compiler.gni
index 5adc470..cc7463e 100644
--- a/build/config/compiler/compiler.gni
+++ b/build/config/compiler/compiler.gni
@@ -13,6 +13,10 @@
   #   0 means no symbols.
   #   -1 means auto-set according to debug/release and platform.
   symbol_level = -1
+
+  # Compile in such a way as to enable profiling of the generated code. For
+  # example, don't omit the frame pointer and leave in symbols.
+  enable_profiling = false
 }
 
 # If it wasn't manually set, set to an appropriate default.
diff --git a/build/config/features.gni b/build/config/features.gni
index 7a8e96457..c9ad3df8 100644
--- a/build/config/features.gni
+++ b/build/config/features.gni
@@ -33,15 +33,9 @@
   # TODO(GYP): Get NaCl linking on other platforms.
   # Also, see if we can always get rid of enable_nacl_untrusted and
   # enable_pnacl and always build them if enable_nacl is true.
-  # The "is_nacl" part of the condition is needed to ensure that
-  # the untrusted code is built properly; arguably it should be
-  # guarded by "is_nacl" directly rather than enable_nacl_untrusted, but
-  # this will go away when Mac and Win are working and we can just use
-  # the commented out logic.
-  # Eventually we want this to be:
-  #   enable_nacl = !is_ios && !is_android && !is_chromecast
-  enable_nacl = (is_linux || is_mac || is_nacl) && current_cpu != "mipsel" &&
-                !is_chromecast
+  # Eventually we want this to be just the first line.
+  enable_nacl = !is_ios && !is_android && !is_chromecast &&
+                current_cpu != "mipsel" && !(is_win && current_cpu != "x64")
   enable_nacl_untrusted = enable_nacl
   enable_pnacl = enable_nacl_untrusted
 
diff --git a/build/config/sysroot.gni b/build/config/sysroot.gni
index debf771..2ca6451 100644
--- a/build/config/sysroot.gni
+++ b/build/config/sysroot.gni
@@ -48,6 +48,18 @@
     # Any other builds don't use a sysroot.
     sysroot = ""
   }
+
+  if (sysroot != "") {
+    _script_arch = current_cpu
+    if (_script_arch == "x86") {
+      _script_arch = "i386"
+    } else if (_script_arch == "x64") {
+      _script_arch = "amd64"
+    }
+    assert(
+        exec_script("//build/dir_exists.py", [ sysroot ], "string") == "True",
+        "Missing sysroot ($sysroot). To fix, run: build/linux/sysroot_scripts/install-sysroot.py --arch=$_script_arch")
+  }
 } else if (is_mac) {
   import("//build/config/mac/mac_sdk.gni")
   sysroot = mac_sdk_path
diff --git a/build/config/ui.gni b/build/config/ui.gni
index 1fc6d0a..fa4f142 100644
--- a/build/config/ui.gni
+++ b/build/config/ui.gni
@@ -69,6 +69,11 @@
   use_glib = false
 }
 
+# Turn off Wayland if glib is enabled.
+if (use_glib) {
+  enable_wayland_server = false
+}
+
 if (is_linux && !use_ozone) {
   use_cairo = true
   use_pango = true
diff --git a/build/config/win/BUILD.gn b/build/config/win/BUILD.gn
index 254000b..bdbf7ea 100644
--- a/build/config/win/BUILD.gn
+++ b/build/config/win/BUILD.gn
@@ -101,7 +101,7 @@
     "_ATL_NO_OPENGL",
     "_WINDOWS",
     "CERT_CHAIN_PARA_HAS_EXTRA_FIELDS",
-    "NTDDI_VERSION=0x06030000",
+    "NTDDI_VERSION=0x0A000000",
     "PSAPI_VERSION=1",
     "WIN32",
     "_SECURE_ATL",
@@ -142,8 +142,8 @@
 # targets need to manually override it for their compiles.
 config("winver") {
   defines = [
-    "_WIN32_WINNT=0x0603",
-    "WINVER=0x0603",
+    "_WIN32_WINNT=0x0A00",
+    "WINVER=0x0A00",
   ]
 }
 
diff --git a/build/gn_migration.gypi b/build/gn_migration.gypi
index dc2a6c5..3861cef9 100644
--- a/build/gn_migration.gypi
+++ b/build/gn_migration.gypi
@@ -727,11 +727,6 @@
             '../tools/win/static_initializers/static_initializers.gyp:static_initializers',
           ],
         }],
-        ['OS=="win" and win_use_allocator_shim==1', {
-          'dependencies': [
-            '../base/allocator/allocator.gyp:allocator_unittests',
-          ]
-        }],
         ['OS=="win" and target_arch=="ia32"', {
           'dependencies': [
             # TODO(GYP): All of these targets need to be ported over.
diff --git a/build/java_apk.gypi b/build/java_apk.gypi
index 2a62d972..93913b24 100644
--- a/build/java_apk.gypi
+++ b/build/java_apk.gypi
@@ -548,6 +548,7 @@
                 '--apk=<(incomplete_apk_path)',
                 '--stamp=<(link_stamp)',
                 '--configuration-name=<(CONFIGURATION_NAME)',
+                '--output-directory=<(PRODUCT_DIR)',
               ],
             },
           ],
@@ -695,6 +696,7 @@
             '--install-record=<(apk_install_record)',
             '--configuration-name=<(CONFIGURATION_NAME)',
             '--android-sdk-tools', '<(android_sdk_tools)',
+            '--output-directory', '<(PRODUCT_DIR)',
           ],
           'conditions': [
             ['create_abi_split == 1', {
diff --git a/build/linux/BUILD.gn b/build/linux/BUILD.gn
index a66d86c..6a1939dd 100644
--- a/build/linux/BUILD.gn
+++ b/build/linux/BUILD.gn
@@ -100,7 +100,7 @@
 }
 
 group("udev") {
-  deps = [
+  public_deps = [
     ":udev0_loader",
     ":udev1_loader",
   ]
diff --git a/build/linux/sysroot_scripts/install-sysroot.py b/build/linux/sysroot_scripts/install-sysroot.py
index e922cb7..b53bd889 100755
--- a/build/linux/sysroot_scripts/install-sysroot.py
+++ b/build/linux/sysroot_scripts/install-sysroot.py
@@ -31,6 +31,10 @@
 import gyp_environment
 
 
+# Its existence signifies an Android checkout.
+ANDROID_ONLY_DIR = os.path.join(SCRIPT_DIR, os.pardir, os.pardir, os.pardir,
+                                'third_party', 'android_tools')
+
 URL_PREFIX = 'http://storage.googleapis.com'
 URL_PATH = 'chrome-linux-sysroot/toolchain'
 REVISION_AMD64 = '402274e42cb72fde4f48a4bb01664d0ad4533c69'
@@ -65,7 +69,7 @@
   return sha1.hexdigest()
 
 
-def DetectArch(gyp_defines, is_android):
+def DetectArch(gyp_defines):
   # Check for optional target_arch and only install for that architecture.
   # If target_arch is not specified, then only install for the host
   # architecture.
@@ -83,9 +87,6 @@
   elif target_arch:
     raise Exception('Unrecognized target_arch: %s' % target_arch)
 
-  if is_android:
-    return 'arm'
-
   # Figure out host arch using build/detect_host_arch.py and
   # set target_arch to host arch
   detected_host_arch = detect_host_arch.HostArch()
@@ -107,32 +108,28 @@
   if options.running_as_hook and not sys.platform.startswith('linux'):
     return 0
 
+  # TODO(agrieve): Make this script not depend on GYP_DEFINES so that it works
+  #     with GN as well.
   gyp_environment.SetEnvironment()
   supplemental_includes = gyp_chromium.GetSupplementalFiles()
   gyp_defines = gyp_chromium.GetGypVars(supplemental_includes)
-  is_android = gyp_defines.get('OS') == 'android'
-
-  if (options.running_as_hook and (not is_android) and
-      (gyp_defines.get('chromeos') or gyp_defines.get('use_sysroot') == '0')):
-    return 0
 
   if options.arch:
     target_arch = options.arch
+  elif os.path.exists(ANDROID_ONLY_DIR):
+    # 32-bit Android builds (the default for target_os="android") require a
+    # 32-bit host sysroot for the v8 snapshot, and a 64-bit sysroot for host
+    # tools.
+    ret = _InstallSysroot('i386')
+    if ret:
+      return ret
+    target_arch = 'amd64'
   else:
-    target_arch = DetectArch(gyp_defines, is_android)
+    target_arch = DetectArch(gyp_defines)
     if not target_arch:
       print 'Unable to detect target architecture'
       return 1
 
-  if is_android:
-    # 32-bit Android builds require a 32-bit host sysroot for the v8 snapshot.
-    if '64' not in target_arch:
-      ret = _InstallSysroot('i386')
-      if ret:
-        return ret
-    # Always need host sysroot (which we assume is x64).
-    target_arch = 'amd64'
-
   return _InstallSysroot(target_arch)
 
 
diff --git a/build/toolchain/gcc_toolchain.gni b/build/toolchain/gcc_toolchain.gni
index 6742f2b..e83b94b 100644
--- a/build/toolchain/gcc_toolchain.gni
+++ b/build/toolchain/gcc_toolchain.gni
@@ -9,7 +9,12 @@
 import("//build/toolchain/toolchain.gni")
 
 # This value will be inherited in the toolchain below.
-concurrent_links = exec_script("get_concurrent_links.py", [], "value")
+if (is_cfi) {
+  concurrent_links =
+      exec_script("get_concurrent_links.py", [ "--lto" ], "value")
+} else {
+  concurrent_links = exec_script("get_concurrent_links.py", [], "value")
+}
 
 # This template defines a toolchain for something that works like gcc
 # (including clang).
diff --git a/build/toolchain/get_concurrent_links.py b/build/toolchain/get_concurrent_links.py
index f8c927b..32294fab 100644
--- a/build/toolchain/get_concurrent_links.py
+++ b/build/toolchain/get_concurrent_links.py
@@ -5,12 +5,13 @@
 # This script computs the number of concurrent links we want to run in the build
 # as a function of machine spec. It's based on GetDefaultConcurrentLinks in GYP.
 
+import optparse
 import os
 import re
 import subprocess
 import sys
 
-def GetDefaultConcurrentLinks():
+def _GetDefaultConcurrentLinks(is_lto):
   # Inherit the legacy environment variable for people that have set it in GYP.
   pool_size = int(os.getenv('GYP_LINK_CONCURRENCY', 0))
   if pool_size:
@@ -49,7 +50,11 @@
           if not match:
             continue
           # Allow 8Gb per link on Linux because Gold is quite memory hungry
-          return max(1, int(match.group(1)) / (8 * (2 ** 20)))
+          # For LTO builds the RAM requirements are even higher
+          # Note: it's 15 GB for LTO build to make sure we get 4 link jobs
+          # for 64 GB, even if the system reports a couple of GBs less.
+          ram_per_link_gb = 15 if is_lto else 8
+          return max(1, int(match.group(1)) / (ram_per_link_gb * (2 ** 20)))
     return 1
   elif sys.platform == 'darwin':
     try:
@@ -63,4 +68,15 @@
     # TODO(scottmg): Implement this for other platforms.
     return 1
 
-print GetDefaultConcurrentLinks()
+def main():
+  parser = optparse.OptionParser()
+  parser.add_option('--lto', action="store_true", default=False,
+                    help='This is an LTO build with higher memory requirements')
+  parser.disable_interspersed_args()
+  options, args = parser.parse_args()
+
+  print _GetDefaultConcurrentLinks(is_lto=options.lto)
+  return 0
+
+if __name__ == '__main__':
+  sys.exit(main())
diff --git a/build/toolchain/win/BUILD.gn b/build/toolchain/win/BUILD.gn
index 2054713b..11f9328c 100644
--- a/build/toolchain/win/BUILD.gn
+++ b/build/toolchain/win/BUILD.gn
@@ -2,6 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import("//build/config/sanitizers/sanitizers.gni")
 import("//build/config/win/visual_studio_version.gni")
 import("//build/toolchain/goma.gni")
 import("//build/toolchain/toolchain.gni")
@@ -24,7 +25,12 @@
 }
 
 # This value will be inherited in the toolchain below.
-concurrent_links = exec_script("../get_concurrent_links.py", [], "value")
+if (is_cfi) {
+  concurrent_links =
+      exec_script("../get_concurrent_links.py", [ "--lto" ], "value")
+} else {
+  concurrent_links = exec_script("../get_concurrent_links.py", [], "value")
+}
 
 # Copy the VS runtime DLL for the default toolchain to the root build directory
 # so things will run.
diff --git a/build/vs_toolchain.py b/build/vs_toolchain.py
index 723106b..eeaaea3 100755
--- a/build/vs_toolchain.py
+++ b/build/vs_toolchain.py
@@ -198,7 +198,7 @@
     return ['49ae4b60d898182fc3f521c2fcda82c453915011']
   else:
     # Default to VS2013.
-    return ['ee7d718ec60c2dc5d255bbe325909c2021a7efef']
+    return ['9ff97c632ae1fee0c98bcd53e71770eb3a0d8deb']
 
 
 def Update(force=False):
diff --git a/cc/BUILD.gn b/cc/BUILD.gn
index 6a1d321c..88e3524 100644
--- a/cc/BUILD.gn
+++ b/cc/BUILD.gn
@@ -563,6 +563,8 @@
     "test/animation_timelines_test_common.h",
     "test/begin_frame_args_test.cc",
     "test/begin_frame_args_test.h",
+    "test/begin_frame_source_test.cc",
+    "test/begin_frame_source_test.h",
     "test/failure_output_surface.cc",
     "test/failure_output_surface.h",
     "test/fake_content_layer_client.cc",
@@ -634,6 +636,7 @@
     "test/layer_tree_settings_for_testing.h",
     "test/layer_tree_test.cc",
     "test/layer_tree_test.h",
+    "test/mock_helper.h",
     "test/mock_occlusion_tracker.h",
     "test/ordered_simple_task_runner.cc",
     "test/ordered_simple_task_runner.h",
@@ -840,7 +843,9 @@
     "scheduler/delay_based_time_source_unittest.cc",
     "scheduler/scheduler_state_machine_unittest.cc",
     "scheduler/scheduler_unittest.cc",
+    "test/begin_frame_source_test_unittest.cc",
     "test/layer_tree_json_parser_unittest.cc",
+    "test/mock_helper_unittest.cc",
     "test/ordered_simple_task_runner_unittest.cc",
     "test/test_web_graphics_context_3d_unittest.cc",
     "tiles/picture_layer_tiling_set_unittest.cc",
diff --git a/cc/base/rtree.cc b/cc/base/rtree.cc
index ca64e87..79a4bcd 100644
--- a/cc/base/rtree.cc
+++ b/cc/base/rtree.cc
@@ -89,14 +89,13 @@
   return BuildRecursive(branches, level + 1);
 }
 
-void RTree::Search(const gfx::RectF& query,
-                   std::vector<size_t>* results) const {
+void RTree::Search(const gfx::Rect& query, std::vector<size_t>* results) const {
   if (num_data_elements_ > 0 && query.Intersects(root_.bounds))
     SearchRecursive(root_.subtree, query, results);
 }
 
 void RTree::SearchRecursive(Node* node,
-                            const gfx::RectF& query,
+                            const gfx::Rect& query,
                             std::vector<size_t>* results) const {
   for (uint16_t i = 0; i < node->num_children; ++i) {
     if (query.Intersects(node->children[i].bounds)) {
diff --git a/cc/base/rtree.h b/cc/base/rtree.h
index f765c353..63f7d14 100644
--- a/cc/base/rtree.h
+++ b/cc/base/rtree.h
@@ -46,7 +46,7 @@
     branches.reserve(items.size());
 
     for (size_t i = 0; i < items.size(); i++) {
-      const gfx::RectF& bounds = bounds_getter(items[i]);
+      const gfx::Rect& bounds = bounds_getter(items[i]);
       if (bounds.IsEmpty())
         continue;
 
@@ -70,10 +70,10 @@
 
   template <typename Container>
   void Build(const Container& items) {
-    Build(items, [](const gfx::RectF& bounds) { return bounds; });
+    Build(items, [](const gfx::Rect& bounds) { return bounds; });
   }
 
-  void Search(const gfx::RectF& query, std::vector<size_t>* results) const;
+  void Search(const gfx::Rect& query, std::vector<size_t>* results) const;
 
  private:
   // These values were empirically determined to produce reasonable performance
@@ -90,7 +90,7 @@
       Node* subtree;
       size_t index;
     };
-    gfx::RectF bounds;
+    gfx::Rect bounds;
   };
 
   struct Node {
@@ -100,7 +100,7 @@
   };
 
   void SearchRecursive(Node* root,
-                       const gfx::RectF& query,
+                       const gfx::Rect& query,
                        std::vector<size_t>* results) const;
 
   // Consumes the input array.
diff --git a/cc/base/rtree_unittest.cc b/cc/base/rtree_unittest.cc
index b703a17..e58c9f6 100644
--- a/cc/base/rtree_unittest.cc
+++ b/cc/base/rtree_unittest.cc
@@ -9,10 +9,10 @@
 namespace cc {
 
 TEST(RTreeTest, NoOverlap) {
-  std::vector<gfx::RectF> rects;
+  std::vector<gfx::Rect> rects;
   for (int y = 0; y < 50; ++y) {
     for (int x = 0; x < 50; ++x) {
-      rects.push_back(gfx::RectF(x, y, 1.f, 1.f));
+      rects.push_back(gfx::Rect(x, y, 1, 1));
     }
   }
 
@@ -20,30 +20,30 @@
   rtree.Build(rects);
 
   std::vector<size_t> results;
-  rtree.Search(gfx::RectF(0.f, 0.f, 50.f, 50.f), &results);
+  rtree.Search(gfx::Rect(0, 0, 50, 50), &results);
   ASSERT_EQ(2500u, results.size());
   for (size_t i = 0; i < 2500; ++i) {
     ASSERT_EQ(results[i], i);
   }
 
   results.clear();
-  rtree.Search(gfx::RectF(0.f, 0.f, 50.f, 49.f), &results);
+  rtree.Search(gfx::Rect(0, 0, 50, 49), &results);
   ASSERT_EQ(2450u, results.size());
   for (size_t i = 0; i < 2450; ++i) {
     ASSERT_EQ(results[i], i);
   }
 
   results.clear();
-  rtree.Search(gfx::RectF(5.2f, 6.3f, 0.1f, 0.2f), &results);
+  rtree.Search(gfx::Rect(5, 6, 1, 1), &results);
   ASSERT_EQ(1u, results.size());
   EXPECT_EQ(6u * 50 + 5u, results[0]);
 }
 
 TEST(RTreeTest, Overlap) {
-  std::vector<gfx::RectF> rects;
+  std::vector<gfx::Rect> rects;
   for (int h = 1; h <= 50; ++h) {
     for (int w = 1; w <= 50; ++w) {
-      rects.push_back(gfx::RectF(0, 0, w, h));
+      rects.push_back(gfx::Rect(0, 0, w, h));
     }
   }
 
@@ -51,14 +51,14 @@
   rtree.Build(rects);
 
   std::vector<size_t> results;
-  rtree.Search(gfx::RectF(0.f, 0.f, 1.f, 1.f), &results);
+  rtree.Search(gfx::Rect(0, 0, 1, 1), &results);
   ASSERT_EQ(2500u, results.size());
   for (size_t i = 0; i < 2500; ++i) {
     ASSERT_EQ(results[i], i);
   }
 
   results.clear();
-  rtree.Search(gfx::RectF(0.f, 49.f, 1.f, 1.f), &results);
+  rtree.Search(gfx::Rect(0, 49, 1, 1), &results);
   ASSERT_EQ(50u, results.size());
   for (size_t i = 0; i < 50; ++i) {
     EXPECT_EQ(results[i], 2450u + i);
diff --git a/cc/cc_tests.gyp b/cc/cc_tests.gyp
index 03f8ae5..5332133 100644
--- a/cc/cc_tests.gyp
+++ b/cc/cc_tests.gyp
@@ -112,7 +112,9 @@
       'scheduler/delay_based_time_source_unittest.cc',
       'scheduler/scheduler_state_machine_unittest.cc',
       'scheduler/scheduler_unittest.cc',
+      'test/begin_frame_source_test_unittest.cc',
       'test/layer_tree_json_parser_unittest.cc',
+      'test/mock_helper_unittest.cc',
       'test/ordered_simple_task_runner_unittest.cc',
       'test/test_web_graphics_context_3d_unittest.cc',
       'tiles/picture_layer_tiling_set_unittest.cc',
@@ -165,6 +167,8 @@
       'test/animation_timelines_test_common.h',
       'test/begin_frame_args_test.cc',
       'test/begin_frame_args_test.h',
+      'test/begin_frame_source_test.cc',
+      'test/begin_frame_source_test.h',
       'test/failure_output_surface.cc',
       'test/failure_output_surface.h',
       'test/fake_content_layer_client.cc',
@@ -236,6 +240,7 @@
       'test/layer_tree_settings_for_testing.h',
       'test/layer_tree_test.cc',
       'test/layer_tree_test.h',
+      'test/mock_helper.h',
       'test/mock_occlusion_tracker.h',
       'test/ordered_simple_task_runner.cc',
       'test/ordered_simple_task_runner.h',
diff --git a/cc/output/direct_renderer.cc b/cc/output/direct_renderer.cc
index 600805a..a55564f 100644
--- a/cc/output/direct_renderer.cc
+++ b/cc/output/direct_renderer.cc
@@ -245,7 +245,9 @@
       break;
     }
   }
-  if (!has_copy_requests) {
+  if (has_copy_requests) {
+    overlay_processor_->SkipProcessForOverlays();
+  } else {
     overlay_processor_->ProcessForOverlays(
         resource_provider_, render_passes_in_draw_order, &frame.overlay_list,
         &frame.ca_layer_overlay_list, &frame.root_damage_rect);
diff --git a/cc/output/overlay_candidate.cc b/cc/output/overlay_candidate.cc
index 658f153..367f316 100644
--- a/cc/output/overlay_candidate.cc
+++ b/cc/output/overlay_candidate.cc
@@ -175,6 +175,7 @@
       use_output_surface_for_resource(false),
       resource_id(0),
       plane_z_order(0),
+      is_unoccluded(false),
       overlay_handled(false) {}
 
 OverlayCandidate::~OverlayCandidate() {}
@@ -228,6 +229,23 @@
 }
 
 // static
+bool OverlayCandidate::IsOccluded(const OverlayCandidate& candidate,
+                                  QuadList::ConstIterator quad_list_begin,
+                                  QuadList::ConstIterator quad_list_end) {
+  // Check that no visible quad overlaps the candidate.
+  for (auto overlap_iter = quad_list_begin; overlap_iter != quad_list_end;
+       ++overlap_iter) {
+    gfx::RectF overlap_rect = MathUtil::MapClippedRect(
+        overlap_iter->shared_quad_state->quad_to_target_transform,
+        gfx::RectF(overlap_iter->rect));
+    if (candidate.display_rect.Intersects(overlap_rect) &&
+        !OverlayCandidate::IsInvisibleQuad(*overlap_iter))
+      return true;
+  }
+  return false;
+}
+
+// static
 bool OverlayCandidate::FromTextureQuad(ResourceProvider* resource_provider,
                                        const TextureDrawQuad* quad,
                                        OverlayCandidate* candidate) {
diff --git a/cc/output/overlay_candidate.h b/cc/output/overlay_candidate.h
index aa42ba11..1a735618 100644
--- a/cc/output/overlay_candidate.h
+++ b/cc/output/overlay_candidate.h
@@ -8,6 +8,7 @@
 #include <vector>
 
 #include "cc/base/cc_export.h"
+#include "cc/quads/render_pass.h"
 #include "cc/resources/resource_format.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/geometry/rect_f.h"
@@ -38,6 +39,12 @@
   // an overlay.
   static bool IsInvisibleQuad(const DrawQuad* quad);
 
+  // Returns true if any any of the quads in the list given by |quad_list_begin|
+  // and |quad_list_end| are visible and on top of |candidate|.
+  static bool IsOccluded(const OverlayCandidate& candidate,
+                         QuadList::ConstIterator quad_list_begin,
+                         QuadList::ConstIterator quad_list_end);
+
   OverlayCandidate();
   ~OverlayCandidate();
 
@@ -66,6 +73,10 @@
   // Stacking order of the overlay plane relative to the main surface,
   // which is 0. Signed to allow for "underlays".
   int plane_z_order;
+  // True if the overlay does not have any visible quads on top of it. Set by
+  // the strategy so the OverlayProcessor can consider subtracting damage caused
+  // by underlay quads.
+  bool is_unoccluded;
 
   // To be modified by the implementer if this candidate can go into
   // an overlay.
diff --git a/cc/output/overlay_processor.cc b/cc/output/overlay_processor.cc
index 40d6da6c..74e68d2 100644
--- a/cc/output/overlay_processor.cc
+++ b/cc/output/overlay_processor.cc
@@ -76,23 +76,48 @@
     if (!strategy->Attempt(resource_provider, render_passes, candidates))
       continue;
 
-    // Subtract on-top overlays from the damage rect, unless the overlays use
-    // the backbuffer as their content (in which case, add their combined rect
-    // back to the damage at the end).
-    gfx::Rect output_surface_overlay_damage_rect;
-    for (const OverlayCandidate& overlay : *candidates) {
-      if (overlay.plane_z_order > 0) {
-        const gfx::Rect overlay_display_rect =
-            ToEnclosedRect(overlay.display_rect);
-        overlay_damage_rect_.Union(overlay_display_rect);
-        damage_rect->Subtract(overlay_display_rect);
-        if (overlay.use_output_surface_for_resource)
-          output_surface_overlay_damage_rect.Union(overlay_display_rect);
-      }
-    }
-    damage_rect->Union(output_surface_overlay_damage_rect);
+    UpdateDamageRect(candidates, damage_rect);
     return;
   }
 }
 
+void OverlayProcessor::SkipProcessForOverlays() {
+  // If overlay processing was skipped for a frame there's no way to be sure
+  // of the state of the previous frame, so reset.
+  previous_frame_underlay_rect_ = gfx::Rect();
+}
+
+// Subtract on-top overlays from the damage rect, unless the overlays use
+// the backbuffer as their content (in which case, add their combined rect
+// back to the damage at the end).
+// Also subtract unoccluded underlays from the damage rect if we know that the
+// same underlay was scheduled on the previous frame. If the renderer decides
+// not to swap the framebuffer there will still be a transparent hole in the
+// previous frame. This only handles the common case of a single underlay quad
+// for fullscreen video.
+void OverlayProcessor::UpdateDamageRect(OverlayCandidateList* candidates,
+                                        gfx::Rect* damage_rect) {
+  gfx::Rect output_surface_overlay_damage_rect;
+  gfx::Rect this_frame_underlay_rect;
+  for (const OverlayCandidate& overlay : *candidates) {
+    if (overlay.plane_z_order > 0) {
+      const gfx::Rect overlay_display_rect =
+          ToEnclosedRect(overlay.display_rect);
+      overlay_damage_rect_.Union(overlay_display_rect);
+      damage_rect->Subtract(overlay_display_rect);
+      if (overlay.use_output_surface_for_resource)
+        output_surface_overlay_damage_rect.Union(overlay_display_rect);
+    } else if (overlay.plane_z_order < 0 && overlay.is_unoccluded &&
+               this_frame_underlay_rect.IsEmpty()) {
+      this_frame_underlay_rect = ToEnclosedRect(overlay.display_rect);
+    }
+  }
+
+  if (this_frame_underlay_rect == previous_frame_underlay_rect_)
+    damage_rect->Subtract(this_frame_underlay_rect);
+  previous_frame_underlay_rect_ = this_frame_underlay_rect;
+
+  damage_rect->Union(output_surface_overlay_damage_rect);
+}
+
 }  // namespace cc
diff --git a/cc/output/overlay_processor.h b/cc/output/overlay_processor.h
index f348fb8..8f3704cd 100644
--- a/cc/output/overlay_processor.h
+++ b/cc/output/overlay_processor.h
@@ -24,9 +24,7 @@
     // Returns false if the strategy cannot be made to work with the
     // current set of render passes. Returns true if the strategy was successful
     // and adds any additional passes necessary to represent overlays to
-    // |render_passes|. Strategy can also optimize |damage_rect| as it seems
-    // fit to reduce GL composition, in case |damage_rect| is obscured by
-    // overlays.
+    // |render_passes|.
     virtual bool Attempt(ResourceProvider* resource_provider,
                          RenderPassList* render_passes,
                          OverlayCandidateList* candidates) = 0;
@@ -46,10 +44,14 @@
                           CALayerOverlayList* ca_layer_overlays,
                           gfx::Rect* damage_rect);
 
+  // Notify the processor that ProcessForOverlays is being skipped this frame.
+  void SkipProcessForOverlays();
+
  protected:
   StrategyList strategies_;
   OutputSurface* surface_;
   gfx::Rect overlay_damage_rect_;
+  gfx::Rect previous_frame_underlay_rect_;
 
  private:
   bool ProcessForCALayers(ResourceProvider* resource_provider,
@@ -57,6 +59,9 @@
                           OverlayCandidateList* overlay_candidates,
                           CALayerOverlayList* ca_layer_overlays,
                           gfx::Rect* damage_rect);
+  // Update |damage_rect| by removing damage casued by |candidates|.
+  void UpdateDamageRect(OverlayCandidateList* candidates,
+                        gfx::Rect* damage_rect);
 
   DISALLOW_COPY_AND_ASSIGN(OverlayProcessor);
 };
diff --git a/cc/output/overlay_strategy_single_on_top.cc b/cc/output/overlay_strategy_single_on_top.cc
index 78e5bf9..10ffcef 100644
--- a/cc/output/overlay_strategy_single_on_top.cc
+++ b/cc/output/overlay_strategy_single_on_top.cc
@@ -40,15 +40,9 @@
     const OverlayCandidate& candidate,
     QuadList::Iterator candidate_iterator) {
   // Check that no prior quads overlap it.
-  for (auto overlap_iter = quad_list->cbegin();
-       overlap_iter != candidate_iterator; ++overlap_iter) {
-    gfx::RectF overlap_rect = MathUtil::MapClippedRect(
-        overlap_iter->shared_quad_state->quad_to_target_transform,
-        gfx::RectF(overlap_iter->rect));
-    if (candidate.display_rect.Intersects(overlap_rect) &&
-        !OverlayCandidate::IsInvisibleQuad(*overlap_iter))
-      return false;
-  }
+  if (OverlayCandidate::IsOccluded(candidate, quad_list->cbegin(),
+                                   candidate_iterator))
+    return false;
 
   // Add the overlay.
   OverlayCandidateList new_candidate_list = *candidate_list;
diff --git a/cc/output/overlay_strategy_underlay.cc b/cc/output/overlay_strategy_underlay.cc
index 9a8a3628..f9bb0391 100644
--- a/cc/output/overlay_strategy_underlay.cc
+++ b/cc/output/overlay_strategy_underlay.cc
@@ -38,6 +38,8 @@
     // If the candidate can be handled by an overlay, create a pass for it. We
     // need to switch out the video quad with a black transparent one.
     if (new_candidate_list.back().overlay_handled) {
+      new_candidate_list.back().is_unoccluded =
+          !OverlayCandidate::IsOccluded(candidate, quad_list.cbegin(), it);
       const SharedQuadState* shared_quad_state = it->shared_quad_state;
       gfx::Rect rect = it->visible_rect;
       SolidColorDrawQuad* replacement =
diff --git a/cc/output/overlay_unittest.cc b/cc/output/overlay_unittest.cc
index 5d1b05f..79742979 100644
--- a/cc/output/overlay_unittest.cc
+++ b/cc/output/overlay_unittest.cc
@@ -1360,7 +1360,8 @@
   EXPECT_EQ(pass_list[0]->quad_list.front()->material, DrawQuad::SOLID_COLOR);
 }
 
-TEST_F(UnderlayTest, DamageRect) {
+// The first time an underlay is scheduled its damage must not be subtracted.
+TEST_F(UnderlayTest, InitialUnderlayDamageNotSubtracted) {
   scoped_ptr<RenderPass> pass = CreateRenderPass();
   CreateFullscreenCandidateQuad(resource_provider_.get(),
                                 pass->shared_quad_state_list.back(),
@@ -1368,30 +1369,114 @@
 
   damage_rect_ = kOverlayRect;
 
-  // Add something behind it.
-  CreateFullscreenOpaqueQuad(resource_provider_.get(),
-                             pass->shared_quad_state_list.back(), pass.get());
-  CreateFullscreenOpaqueQuad(resource_provider_.get(),
-                             pass->shared_quad_state_list.back(), pass.get());
-
   RenderPassList pass_list;
   pass_list.push_back(std::move(pass));
 
-  // Check for potential candidates.
   OverlayCandidateList candidate_list;
-
-  // Primary plane.
-  OverlayCandidate output_surface_plane;
-  output_surface_plane.display_rect = gfx::RectF(kOverlayRect);
-  output_surface_plane.quad_rect_in_target_space = kOverlayRect;
-  output_surface_plane.use_output_surface_for_resource = true;
-  output_surface_plane.overlay_handled = true;
-  candidate_list.push_back(output_surface_plane);
-
   overlay_processor_->ProcessForOverlays(resource_provider_.get(), &pass_list,
                                          &candidate_list, nullptr,
                                          &damage_rect_);
-  DCHECK(!damage_rect_.IsEmpty());
+
+  EXPECT_EQ(kOverlayRect, damage_rect_);
+}
+
+// An identical underlay for two frames in a row means the damage can be
+// subtracted the second time.
+TEST_F(UnderlayTest, DamageSubtractedForConsecutiveIdenticalUnderlays) {
+  for (int i = 0; i < 2; ++i) {
+    scoped_ptr<RenderPass> pass = CreateRenderPass();
+    CreateFullscreenCandidateQuad(resource_provider_.get(),
+                                  pass->shared_quad_state_list.back(),
+                                  pass.get());
+
+    damage_rect_ = kOverlayRect;
+
+    // Add something behind it.
+    CreateFullscreenOpaqueQuad(resource_provider_.get(),
+                               pass->shared_quad_state_list.back(), pass.get());
+
+    RenderPassList pass_list;
+    pass_list.push_back(pass.Pass());
+    OverlayCandidateList candidate_list;
+    overlay_processor_->ProcessForOverlays(resource_provider_.get(), &pass_list,
+                                           &candidate_list, nullptr,
+                                           &damage_rect_);
+  }
+
+  // The second time the same overlay rect is scheduled it will be subtracted
+  // from the damage rect.
+  EXPECT_TRUE(damage_rect_.IsEmpty());
+}
+
+// Underlay damage can only be subtracted if the previous frame's underlay
+// was the same rect.
+TEST_F(UnderlayTest, DamageNotSubtractedForNonIdenticalConsecutiveUnderlays) {
+  gfx::Rect overlay_rects[] = {kOverlayBottomRightRect, kOverlayRect};
+  for (int i = 0; i < 2; ++i) {
+    scoped_ptr<RenderPass> pass = CreateRenderPass();
+
+    CreateCandidateQuadAt(resource_provider_.get(),
+                          pass->shared_quad_state_list.back(), pass.get(),
+                          overlay_rects[i]);
+
+    damage_rect_ = overlay_rects[i];
+
+    RenderPassList pass_list;
+    pass_list.push_back(pass.Pass());
+    OverlayCandidateList candidate_list;
+    overlay_processor_->ProcessForOverlays(resource_provider_.get(), &pass_list,
+                                           &candidate_list, nullptr,
+                                           &damage_rect_);
+
+    EXPECT_EQ(overlay_rects[i], damage_rect_);
+  }
+}
+
+TEST_F(UnderlayTest, DamageNotSubtractedWhenQuadsAboveOverlap) {
+  for (int i = 0; i < 2; ++i) {
+    scoped_ptr<RenderPass> pass = CreateRenderPass();
+    // Add an overlapping quad above the candidate.
+    CreateFullscreenOpaqueQuad(resource_provider_.get(),
+                               pass->shared_quad_state_list.back(), pass.get());
+    CreateFullscreenCandidateQuad(resource_provider_.get(),
+                                  pass->shared_quad_state_list.back(),
+                                  pass.get());
+
+    damage_rect_ = kOverlayRect;
+
+    RenderPassList pass_list;
+    pass_list.push_back(pass.Pass());
+    OverlayCandidateList candidate_list;
+    overlay_processor_->ProcessForOverlays(resource_provider_.get(), &pass_list,
+                                           &candidate_list, nullptr,
+                                           &damage_rect_);
+  }
+
+  EXPECT_EQ(kOverlayRect, damage_rect_);
+}
+
+TEST_F(UnderlayTest, DamageSubtractedWhenQuadsAboveDontOverlap) {
+  for (int i = 0; i < 2; ++i) {
+    scoped_ptr<RenderPass> pass = CreateRenderPass();
+    // Add a non-overlapping quad above the candidate.
+    CreateOpaqueQuadAt(resource_provider_.get(),
+                       pass->shared_quad_state_list.back(), pass.get(),
+                       kOverlayTopLeftRect);
+    CreateCandidateQuadAt(resource_provider_.get(),
+                          pass->shared_quad_state_list.back(), pass.get(),
+                          kOverlayBottomRightRect);
+
+    damage_rect_ = kOverlayBottomRightRect;
+
+    RenderPassList pass_list;
+    pass_list.push_back(pass.Pass());
+    OverlayCandidateList candidate_list;
+    overlay_processor_->ProcessForOverlays(resource_provider_.get(), &pass_list,
+                                           &candidate_list, nullptr,
+                                           &damage_rect_);
+  }
+
+  EXPECT_TRUE(damage_rect_.IsEmpty());
 }
 
 OverlayCandidateList BackbufferOverlayList(const RenderPass* root_render_pass) {
diff --git a/cc/output/renderer.cc b/cc/output/renderer.cc
index 7fe0ffb..a0812c6 100644
--- a/cc/output/renderer.cc
+++ b/cc/output/renderer.cc
@@ -26,12 +26,12 @@
       max_texture_size(0),
       using_shared_memory_resources(false),
       using_partial_swap(false),
+      allow_empty_swap(false),
       using_egl_image(false),
       using_image(false),
       using_discard_framebuffer(false),
       allow_rasterize_on_demand(false),
-      max_msaa_samples(0) {
-}
+      max_msaa_samples(0) {}
 
 RendererCapabilitiesImpl::~RendererCapabilitiesImpl() {}
 
diff --git a/cc/playback/discardable_image_map.cc b/cc/playback/discardable_image_map.cc
index 1333475..e109e2be 100644
--- a/cc/playback/discardable_image_map.cc
+++ b/cc/playback/discardable_image_map.cc
@@ -39,7 +39,7 @@
   DiscardableImagesMetadataCanvas(
       int width,
       int height,
-      std::vector<std::pair<DrawImage, gfx::RectF>>* image_set)
+      std::vector<std::pair<DrawImage, gfx::Rect>>* image_set)
       : SkNWayCanvas(width, height),
         image_set_(image_set),
         canvas_bounds_(SkRect::MakeIWH(width, height)) {}
@@ -99,11 +99,11 @@
       }
       image_set_->push_back(
           std::make_pair(DrawImage(image, ExtractScale(matrix), filter_quality),
-                         gfx::SkRectToRectF(rect)));
+                         gfx::ToEnclosingRect(gfx::SkRectToRectF(rect))));
     }
   }
 
-  std::vector<std::pair<DrawImage, gfx::RectF>>* image_set_;
+  std::vector<std::pair<DrawImage, gfx::Rect>>* image_set_;
   const SkRect canvas_bounds_;
 };
 
@@ -121,8 +121,10 @@
 }
 
 void DiscardableImageMap::EndGeneratingMetadata() {
-  images_rtree_.Build(
-      all_images_, [](const PositionDrawImage& image) { return image.second; });
+  images_rtree_.Build(all_images_,
+                      [](const std::pair<DrawImage, gfx::Rect>& image) {
+                        return image.second;
+                      });
 }
 
 void DiscardableImageMap::GetDiscardableImagesInRect(
@@ -130,7 +132,7 @@
     float raster_scale,
     std::vector<DrawImage>* images) const {
   std::vector<size_t> indices;
-  images_rtree_.Search(gfx::RectF(rect), &indices);
+  images_rtree_.Search(rect, &indices);
   for (size_t index : indices)
     images->push_back(all_images_[index].first.ApplyScale(raster_scale));
 }
diff --git a/cc/playback/discardable_image_map.h b/cc/playback/discardable_image_map.h
index db6b17fe..0306e1b 100644
--- a/cc/playback/discardable_image_map.h
+++ b/cc/playback/discardable_image_map.h
@@ -49,12 +49,11 @@
  private:
   friend class ScopedMetadataGenerator;
   friend class DiscardableImageMapTest;
-  using PositionDrawImage = std::pair<DrawImage, gfx::RectF>;
 
   scoped_ptr<SkCanvas> BeginGeneratingMetadata(const gfx::Size& bounds);
   void EndGeneratingMetadata();
 
-  std::vector<PositionDrawImage> all_images_;
+  std::vector<std::pair<DrawImage, gfx::Rect>> all_images_;
   RTree images_rtree_;
 };
 
diff --git a/cc/playback/discardable_image_map_unittest.cc b/cc/playback/discardable_image_map_unittest.cc
index f68b6963..70253caa 100644
--- a/cc/playback/discardable_image_map_unittest.cc
+++ b/cc/playback/discardable_image_map_unittest.cc
@@ -21,10 +21,10 @@
 namespace {
 
 struct PositionDrawImage {
-  PositionDrawImage(const SkImage* image, const gfx::RectF& image_rect)
+  PositionDrawImage(const SkImage* image, const gfx::Rect& image_rect)
       : image(image), image_rect(image_rect) {}
   const SkImage* image;
-  gfx::RectF image_rect;
+  gfx::Rect image_rect;
 };
 
 }  // namespace
@@ -38,7 +38,7 @@
     image_map.GetDiscardableImagesInRect(rect, 1.f, &draw_images);
 
     std::vector<size_t> indices;
-    image_map.images_rtree_.Search(gfx::RectF(rect), &indices);
+    image_map.images_rtree_.Search(rect, &indices);
     std::vector<PositionDrawImage> position_draw_images;
     for (size_t index : indices) {
       position_draw_images.push_back(
@@ -104,7 +104,7 @@
         EXPECT_EQ(1u, images.size()) << x << " " << y;
         EXPECT_TRUE(images[0].image == discardable_image[y][x].get())
             << x << " " << y;
-        EXPECT_EQ(gfx::RectF(x * 512 + 6, y * 512 + 6, 500, 500),
+        EXPECT_EQ(gfx::Rect(x * 512 + 6, y * 512 + 6, 500, 500),
                   images[0].image_rect);
       } else {
         EXPECT_EQ(0u, images.size()) << x << " " << y;
@@ -117,14 +117,14 @@
       GetDiscardableImagesInRect(image_map, gfx::Rect(512, 512, 2048, 2048));
   EXPECT_EQ(4u, images.size());
   EXPECT_TRUE(images[0].image == discardable_image[1][2].get());
-  EXPECT_EQ(gfx::RectF(2 * 512 + 6, 512 + 6, 500, 500), images[0].image_rect);
+  EXPECT_EQ(gfx::Rect(2 * 512 + 6, 512 + 6, 500, 500), images[0].image_rect);
   EXPECT_TRUE(images[1].image == discardable_image[2][1].get());
-  EXPECT_EQ(gfx::RectF(512 + 6, 2 * 512 + 6, 500, 500), images[1].image_rect);
+  EXPECT_EQ(gfx::Rect(512 + 6, 2 * 512 + 6, 500, 500), images[1].image_rect);
   EXPECT_TRUE(images[2].image == discardable_image[2][3].get());
-  EXPECT_EQ(gfx::RectF(3 * 512 + 6, 2 * 512 + 6, 500, 500),
+  EXPECT_EQ(gfx::Rect(3 * 512 + 6, 2 * 512 + 6, 500, 500),
             images[2].image_rect);
   EXPECT_TRUE(images[3].image == discardable_image[3][2].get());
-  EXPECT_EQ(gfx::RectF(2 * 512 + 6, 3 * 512 + 6, 500, 500),
+  EXPECT_EQ(gfx::Rect(2 * 512 + 6, 3 * 512 + 6, 500, 500),
             images[3].image_rect);
 }
 
@@ -181,7 +181,7 @@
         EXPECT_EQ(1u, images.size()) << x << " " << y;
         EXPECT_TRUE(images[0].image == discardable_image[y][x].get())
             << x << " " << y;
-        EXPECT_EQ(gfx::RectF(1024 + x * 512 + 6, y * 512 + 6, 500, 500),
+        EXPECT_EQ(gfx::Rect(1024 + x * 512 + 6, y * 512 + 6, 500, 500),
                   images[0].image_rect);
       } else {
         EXPECT_EQ(0u, images.size()) << x << " " << y;
@@ -194,16 +194,16 @@
         image_map, gfx::Rect(1024 + 512, 512, 2048, 2048));
     EXPECT_EQ(4u, images.size());
     EXPECT_TRUE(images[0].image == discardable_image[1][2].get());
-    EXPECT_EQ(gfx::RectF(1024 + 2 * 512 + 6, 512 + 6, 500, 500),
+    EXPECT_EQ(gfx::Rect(1024 + 2 * 512 + 6, 512 + 6, 500, 500),
               images[0].image_rect);
     EXPECT_TRUE(images[1].image == discardable_image[2][1].get());
-    EXPECT_EQ(gfx::RectF(1024 + 512 + 6, 2 * 512 + 6, 500, 500),
+    EXPECT_EQ(gfx::Rect(1024 + 512 + 6, 2 * 512 + 6, 500, 500),
               images[1].image_rect);
     EXPECT_TRUE(images[2].image == discardable_image[2][3].get());
-    EXPECT_EQ(gfx::RectF(1024 + 3 * 512 + 6, 2 * 512 + 6, 500, 500),
+    EXPECT_EQ(gfx::Rect(1024 + 3 * 512 + 6, 2 * 512 + 6, 500, 500),
               images[2].image_rect);
     EXPECT_TRUE(images[3].image == discardable_image[3][2].get());
-    EXPECT_EQ(gfx::RectF(1024 + 2 * 512 + 6, 3 * 512 + 6, 500, 500),
+    EXPECT_EQ(gfx::Rect(1024 + 2 * 512 + 6, 3 * 512 + 6, 500, 500),
               images[3].image_rect);
   }
 
@@ -281,7 +281,7 @@
         EXPECT_EQ(1u, images.size()) << x << " " << y;
         EXPECT_TRUE(images[0].image == discardable_image[y][x].get())
             << x << " " << y;
-        EXPECT_EQ(gfx::RectF(x * 512 + 6, y * 512 + 6, 500, 500),
+        EXPECT_EQ(gfx::Rect(x * 512 + 6, y * 512 + 6, 500, 500),
                   images[0].image_rect);
       } else {
         EXPECT_EQ(0u, images.size()) << x << " " << y;
@@ -319,7 +319,7 @@
       GetDiscardableImagesInRect(image_map, gfx::Rect(0, 0, 1, 1));
   EXPECT_EQ(1u, images.size());
   EXPECT_TRUE(images[0].image == discardable_image.get());
-  EXPECT_EQ(gfx::RectF(0, 0, 1 << 25, 1 << 25), images[0].image_rect);
+  EXPECT_EQ(gfx::Rect(0, 0, 1 << 25, 1 << 25), images[0].image_rect);
 }
 
 }  // namespace cc
diff --git a/cc/scheduler/begin_frame_source.cc b/cc/scheduler/begin_frame_source.cc
index 1ee862b..26819831 100644
--- a/cc/scheduler/begin_frame_source.cc
+++ b/cc/scheduler/begin_frame_source.cc
@@ -13,18 +13,6 @@
 #include "cc/scheduler/delay_based_time_source.h"
 #include "cc/scheduler/scheduler.h"
 
-#ifdef NDEBUG
-#define DEBUG_FRAMES(...)
-#else
-#define DEBUG_FRAMES(name, arg1_name, arg1_val, arg2_name, arg2_val)   \
-  TRACE_EVENT2(TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler.frames"), \
-               name,                                                   \
-               arg1_name,                                              \
-               arg1_val,                                               \
-               arg2_name,                                              \
-               arg2_val);
-#endif
-
 namespace cc {
 
 // BeginFrameObserverBase -----------------------------------------------
diff --git a/cc/scheduler/begin_frame_source.h b/cc/scheduler/begin_frame_source.h
index f6f1a78..87ed17f6 100644
--- a/cc/scheduler/begin_frame_source.h
+++ b/cc/scheduler/begin_frame_source.h
@@ -13,6 +13,14 @@
 #include "cc/output/begin_frame_args.h"
 #include "cc/scheduler/delay_based_time_source.h"
 
+#ifdef NDEBUG
+#define DEBUG_FRAMES(...)
+#else
+#define DEBUG_FRAMES(name, arg1_name, arg1_val, arg2_name, arg2_val)         \
+  TRACE_EVENT2(TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler.frames"), name, \
+               arg1_name, arg1_val, arg2_name, arg2_val);
+#endif
+
 namespace cc {
 
 // (Pure) Interface for observing BeginFrame messages from BeginFrameSource
diff --git a/cc/scheduler/begin_frame_source_unittest.cc b/cc/scheduler/begin_frame_source_unittest.cc
index 2c12ca90..afc3b30 100644
--- a/cc/scheduler/begin_frame_source_unittest.cc
+++ b/cc/scheduler/begin_frame_source_unittest.cc
@@ -2,173 +2,19 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include <deque>
-#include <string>
+#include "cc/scheduler/begin_frame_source.h"
 
 #include "base/basictypes.h"
 #include "base/test/test_simple_task_runner.h"
-#include "cc/scheduler/begin_frame_source.h"
 #include "cc/test/begin_frame_args_test.h"
+#include "cc/test/begin_frame_source_test.h"
 #include "cc/test/scheduler_test_common.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-// Macros to help set up expected calls on the MockBeginFrameObserver.
-#define EXPECT_BEGIN_FRAME_DROP(obs, frame_time, deadline, interval)       \
-  {                                                                        \
-    ::testing::Expectation exp =                                           \
-        EXPECT_CALL((obs), OnBeginFrame(CreateBeginFrameArgsForTesting(    \
-                               BEGINFRAME_FROM_HERE, frame_time, deadline, \
-                               interval))).InSequence((obs).sequence);     \
-  }
-
-#define EXPECT_BEGIN_FRAME_USED(obs, frame_time, deadline, interval)       \
-  {                                                                        \
-    BeginFrameArgs args = CreateBeginFrameArgsForTesting(                  \
-        BEGINFRAME_FROM_HERE, frame_time, deadline, interval);             \
-    ::testing::Expectation exp =                                           \
-        EXPECT_CALL((obs), OnBeginFrame(args)).InSequence((obs).sequence); \
-    EXPECT_CALL((obs), LastUsedBeginFrameArgs())                           \
-        .Times(::testing::AnyNumber())                                     \
-        .After(exp)                                                        \
-        .WillRepeatedly(::testing::Return(args));                          \
-  }
-
-// Macros to send BeginFrameArgs on a FakeBeginFrameSink (and verify resulting
-// observer behaviour).
-#define SEND_BEGIN_FRAME(args_equal_to, source, frame_time, deadline, \
-                         interval)                                    \
-  {                                                                   \
-    BeginFrameArgs old_args = (source).TestLastUsedBeginFrameArgs();  \
-    BeginFrameArgs new_args = CreateBeginFrameArgsForTesting(         \
-        BEGINFRAME_FROM_HERE, frame_time, deadline, interval);        \
-    ASSERT_FALSE(old_args == new_args);                               \
-    (source).TestOnBeginFrame(new_args);                              \
-    EXPECT_EQ(args_equal_to, (source).TestLastUsedBeginFrameArgs());  \
-  }
-
-// When dropping LastUsedBeginFrameArgs **shouldn't** change.
-#define SEND_BEGIN_FRAME_DROP(source, frame_time, deadline, interval) \
-  SEND_BEGIN_FRAME(old_args, source, frame_time, deadline, interval);
-
-// When used LastUsedBeginFrameArgs **should** be updated.
-#define SEND_BEGIN_FRAME_USED(source, frame_time, deadline, interval) \
-  SEND_BEGIN_FRAME(new_args, source, frame_time, deadline, interval);
-
 namespace cc {
 namespace {
 
-class MockBeginFrameObserver : public BeginFrameObserver {
- public:
-  MOCK_METHOD1(OnBeginFrame, void(const BeginFrameArgs&));
-  MOCK_CONST_METHOD0(LastUsedBeginFrameArgs, const BeginFrameArgs());
-
-  virtual void AsValueInto(base::trace_event::TracedValue* dict) const {
-    dict->SetString("type", "MockBeginFrameObserver");
-    dict->BeginDictionary("last_begin_frame_args");
-    LastUsedBeginFrameArgs().AsValueInto(dict);
-    dict->EndDictionary();
-  }
-
-  // A value different from the normal default returned by a BeginFrameObserver
-  // so it is easiable traced back here.
-  static const BeginFrameArgs kDefaultBeginFrameArgs;
-
-  MockBeginFrameObserver() {
-    // Set a "default" value returned by LastUsedBeginFrameArgs so that gMock
-    // doesn't fail an assert and instead returns useful information.
-    EXPECT_CALL(*this, LastUsedBeginFrameArgs())
-        .Times(::testing::AnyNumber())
-        .InSequence(sequence)
-        .WillRepeatedly(::testing::Return(kDefaultBeginFrameArgs));
-  }
-  virtual ~MockBeginFrameObserver() {}
-
-  ::testing::Sequence sequence;
-};
-
-TEST(MockBeginFrameObserverTest, ExpectOnBeginFrame) {
-  ::testing::NiceMock<MockBeginFrameObserver> obs;
-  EXPECT_BEGIN_FRAME_USED(obs, 100, 200, 300);
-  EXPECT_BEGIN_FRAME_USED(obs, 400, 600, 300);
-  EXPECT_BEGIN_FRAME_USED(obs, 700, 900, 300);
-
-  EXPECT_EQ(obs.LastUsedBeginFrameArgs(),
-            MockBeginFrameObserver::kDefaultBeginFrameArgs);
-
-  obs.OnBeginFrame(CreateBeginFrameArgsForTesting(
-      BEGINFRAME_FROM_HERE, 100, 200,
-      300));  // One call to LastUsedBeginFrameArgs
-  EXPECT_EQ(
-      obs.LastUsedBeginFrameArgs(),
-      CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 100, 200, 300));
-
-  obs.OnBeginFrame(CreateBeginFrameArgsForTesting(
-      BEGINFRAME_FROM_HERE, 400, 600,
-      300));  // Multiple calls to LastUsedBeginFrameArgs
-  EXPECT_EQ(
-      obs.LastUsedBeginFrameArgs(),
-      CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 400, 600, 300));
-  EXPECT_EQ(
-      obs.LastUsedBeginFrameArgs(),
-      CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 400, 600, 300));
-
-  obs.OnBeginFrame(CreateBeginFrameArgsForTesting(
-      BEGINFRAME_FROM_HERE, 700, 900,
-      300));  // No calls to LastUsedBeginFrameArgs
-}
-
-TEST(MockBeginFrameObserverTest, ExpectOnBeginFrameStatus) {
-  ::testing::NiceMock<MockBeginFrameObserver> obs;
-  EXPECT_BEGIN_FRAME_USED(obs, 100, 200, 300);
-  EXPECT_BEGIN_FRAME_DROP(obs, 400, 600, 300);
-  EXPECT_BEGIN_FRAME_DROP(obs, 450, 650, 300);
-  EXPECT_BEGIN_FRAME_USED(obs, 700, 900, 300);
-
-  EXPECT_EQ(obs.LastUsedBeginFrameArgs(),
-            MockBeginFrameObserver::kDefaultBeginFrameArgs);
-
-  // Used
-  obs.OnBeginFrame(
-      CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 100, 200, 300));
-  EXPECT_EQ(
-      obs.LastUsedBeginFrameArgs(),
-      CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 100, 200, 300));
-
-  // Dropped
-  obs.OnBeginFrame(
-      CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 400, 600, 300));
-  EXPECT_EQ(
-      obs.LastUsedBeginFrameArgs(),
-      CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 100, 200, 300));
-
-  // Dropped
-  obs.OnBeginFrame(
-      CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 450, 650, 300));
-  EXPECT_EQ(
-      obs.LastUsedBeginFrameArgs(),
-      CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 100, 200, 300));
-
-  // Used
-  obs.OnBeginFrame(
-      CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 700, 900, 300));
-  EXPECT_EQ(
-      obs.LastUsedBeginFrameArgs(),
-      CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 700, 900, 300));
-}
-
-const BeginFrameArgs MockBeginFrameObserver::kDefaultBeginFrameArgs =
-    CreateBeginFrameArgsForTesting(
-#ifdef NDEBUG
-        nullptr,
-#else
-        FROM_HERE_WITH_EXPLICIT_FUNCTION(
-            "MockBeginFrameObserver::kDefaultBeginFrameArgs"),
-#endif
-        -1,
-        -1,
-        -1);
-
 // BeginFrameObserverBase testing ---------------------------------------
 class MockMinimalBeginFrameObserverBase : public BeginFrameObserverBase {
  public:
diff --git a/cc/test/begin_frame_source_test.cc b/cc/test/begin_frame_source_test.cc
new file mode 100644
index 0000000..ef1c033
--- /dev/null
+++ b/cc/test/begin_frame_source_test.cc
@@ -0,0 +1,42 @@
+// 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.
+
+#include "cc/test/begin_frame_source_test.h"
+
+#include "cc/test/begin_frame_args_test.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace cc {
+
+void MockBeginFrameObserver::AsValueInto(
+    base::trace_event::TracedValue* dict) const {
+  dict->SetString("type", "MockBeginFrameObserver");
+  dict->BeginDictionary("last_begin_frame_args");
+  last_begin_frame_args.AsValueInto(dict);
+  dict->EndDictionary();
+}
+
+MockBeginFrameObserver::MockBeginFrameObserver()
+    : last_begin_frame_args(kDefaultBeginFrameArgs) {
+  EXPECT_CALL(*this, LastUsedBeginFrameArgs())
+      .Times(::testing::AnyNumber())
+      .WillRepeatedly(::testing::ReturnPointee(&last_begin_frame_args));
+}
+
+MockBeginFrameObserver::~MockBeginFrameObserver() {}
+
+const BeginFrameArgs MockBeginFrameObserver::kDefaultBeginFrameArgs =
+    CreateBeginFrameArgsForTesting(
+#ifdef NDEBUG
+        nullptr,
+#else
+        FROM_HERE_WITH_EXPLICIT_FUNCTION(
+            "MockBeginFrameObserver::kDefaultBeginFrameArgs"),
+#endif
+        -1,
+        -1,
+        -1);
+
+}  // namespace cc
diff --git a/cc/test/begin_frame_source_test.h b/cc/test/begin_frame_source_test.h
new file mode 100644
index 0000000..98f5d90f
--- /dev/null
+++ b/cc/test/begin_frame_source_test.h
@@ -0,0 +1,73 @@
+// 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.
+
+#ifndef CC_TEST_BEGIN_FRAME_SOURCE_TEST_H_
+#define CC_TEST_BEGIN_FRAME_SOURCE_TEST_H_
+
+#include "base/basictypes.h"
+#include "base/trace_event/trace_event_argument.h"
+#include "cc/scheduler/begin_frame_source.h"
+#include "cc/test/begin_frame_args_test.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+// Macros to help set up expected calls on the MockBeginFrameObserver.
+#define EXPECT_BEGIN_FRAME_DROP(obs, frame_time, deadline, interval)      \
+  EXPECT_CALL((obs),                                                      \
+              OnBeginFrame(CreateBeginFrameArgsForTesting(                \
+                  BEGINFRAME_FROM_HERE, frame_time, deadline, interval))) \
+      .Times(1)                                                           \
+      .InSequence((obs).sequence)
+
+#define EXPECT_BEGIN_FRAME_USED(obs, frame_time, deadline, interval)      \
+  EXPECT_CALL((obs),                                                      \
+              OnBeginFrame(CreateBeginFrameArgsForTesting(                \
+                  BEGINFRAME_FROM_HERE, frame_time, deadline, interval))) \
+      .InSequence((obs).sequence)                                         \
+      .WillOnce(::testing::SaveArg<0>(&((obs).last_begin_frame_args)))
+
+// Macros to send BeginFrameArgs on a FakeBeginFrameSink (and verify resulting
+// observer behaviour).
+#define SEND_BEGIN_FRAME(args_equal_to, source, frame_time, deadline, \
+                         interval)                                    \
+  {                                                                   \
+    BeginFrameArgs old_args = (source).TestLastUsedBeginFrameArgs();  \
+    BeginFrameArgs new_args = CreateBeginFrameArgsForTesting(         \
+        BEGINFRAME_FROM_HERE, frame_time, deadline, interval);        \
+    ASSERT_FALSE(old_args == new_args);                               \
+    (source).TestOnBeginFrame(new_args);                              \
+    EXPECT_EQ(args_equal_to, (source).TestLastUsedBeginFrameArgs());  \
+  }
+
+// When dropping LastUsedBeginFrameArgs **shouldn't** change.
+#define SEND_BEGIN_FRAME_DROP(source, frame_time, deadline, interval) \
+  SEND_BEGIN_FRAME(old_args, source, frame_time, deadline, interval);
+
+// When used LastUsedBeginFrameArgs **should** be updated.
+#define SEND_BEGIN_FRAME_USED(source, frame_time, deadline, interval) \
+  SEND_BEGIN_FRAME(new_args, source, frame_time, deadline, interval);
+
+namespace cc {
+
+class MockBeginFrameObserver : public BeginFrameObserver {
+ public:
+  MOCK_METHOD1(OnBeginFrame, void(const BeginFrameArgs&));
+  MOCK_CONST_METHOD0(LastUsedBeginFrameArgs, const BeginFrameArgs());
+
+  virtual void AsValueInto(base::trace_event::TracedValue* dict) const;
+
+  // A value different from the normal default returned by a BeginFrameObserver
+  // so it is easiable traced back here.
+  static const BeginFrameArgs kDefaultBeginFrameArgs;
+
+  MockBeginFrameObserver();
+  virtual ~MockBeginFrameObserver();
+
+  BeginFrameArgs last_begin_frame_args;
+  ::testing::Sequence sequence;
+};
+
+}  // namespace cc
+
+#endif  // CC_TEST_BEGIN_FRAME_SOURCE_TEST_H_
diff --git a/cc/test/begin_frame_source_test_unittest.cc b/cc/test/begin_frame_source_test_unittest.cc
new file mode 100644
index 0000000..601da31
--- /dev/null
+++ b/cc/test/begin_frame_source_test_unittest.cc
@@ -0,0 +1,124 @@
+// 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.
+
+#include "cc/test/begin_frame_source_test.h"
+
+#include "cc/test/begin_frame_args_test.h"
+#include "cc/test/mock_helper.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace cc {
+namespace {
+TEST(MockBeginFrameObserverTest, FailOnMissingCalls) {
+  EXPECT_MOCK_FAILURE({
+    ::testing::NiceMock<MockBeginFrameObserver> obs;
+    EXPECT_BEGIN_FRAME_USED(obs, 100, 200, 300);
+    EXPECT_BEGIN_FRAME_USED(obs, 400, 600, 300);
+
+    obs.OnBeginFrame(
+        CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 400, 600, 300));
+  });
+}
+
+TEST(MockBeginFrameObserverTest, FailOnMultipleCalls) {
+  EXPECT_MOCK_FAILURE({
+    ::testing::NiceMock<MockBeginFrameObserver> obs;
+    EXPECT_BEGIN_FRAME_USED(obs, 100, 200, 300);
+    EXPECT_BEGIN_FRAME_USED(obs, 400, 600, 300);
+
+    obs.OnBeginFrame(
+        CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 100, 200, 300));
+    obs.OnBeginFrame(
+        CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 100, 200, 300));
+    obs.OnBeginFrame(
+        CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 400, 600, 300));
+  });
+}
+
+TEST(MockBeginFrameObserverTest, FailOnWrongCallOrder) {
+  EXPECT_MOCK_FAILURE({
+    ::testing::NiceMock<MockBeginFrameObserver> obs;
+    EXPECT_BEGIN_FRAME_USED(obs, 100, 200, 300);
+    EXPECT_BEGIN_FRAME_USED(obs, 400, 600, 300);
+
+    obs.OnBeginFrame(
+        CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 400, 600, 300));
+    obs.OnBeginFrame(
+        CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 100, 200, 300));
+  });
+}
+
+TEST(MockBeginFrameObserverTest, ExpectOnBeginFrame) {
+  ::testing::NiceMock<MockBeginFrameObserver> obs;
+  EXPECT_BEGIN_FRAME_USED(obs, 100, 200, 300);
+  EXPECT_BEGIN_FRAME_USED(obs, 400, 600, 300);
+  EXPECT_BEGIN_FRAME_USED(obs, 700, 900, 300);
+
+  EXPECT_EQ(obs.LastUsedBeginFrameArgs(),
+            MockBeginFrameObserver::kDefaultBeginFrameArgs);
+
+  obs.OnBeginFrame(CreateBeginFrameArgsForTesting(
+      BEGINFRAME_FROM_HERE, 100, 200,
+      300));  // One call to LastUsedBeginFrameArgs
+  EXPECT_EQ(
+      obs.LastUsedBeginFrameArgs(),
+      CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 100, 200, 300));
+
+  obs.OnBeginFrame(CreateBeginFrameArgsForTesting(
+      BEGINFRAME_FROM_HERE, 400, 600,
+      300));  // Multiple calls to LastUsedBeginFrameArgs
+  EXPECT_EQ(
+      obs.LastUsedBeginFrameArgs(),
+      CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 400, 600, 300));
+  EXPECT_EQ(
+      obs.LastUsedBeginFrameArgs(),
+      CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 400, 600, 300));
+
+  obs.OnBeginFrame(CreateBeginFrameArgsForTesting(
+      BEGINFRAME_FROM_HERE, 700, 900,
+      300));  // No calls to LastUsedBeginFrameArgs
+}
+
+TEST(MockBeginFrameObserverTest, ExpectOnBeginFrameStatus) {
+  ::testing::NiceMock<MockBeginFrameObserver> obs;
+  EXPECT_BEGIN_FRAME_USED(obs, 100, 200, 300);
+  EXPECT_BEGIN_FRAME_DROP(obs, 400, 600, 300);
+  EXPECT_BEGIN_FRAME_DROP(obs, 450, 650, 300);
+  EXPECT_BEGIN_FRAME_USED(obs, 700, 900, 300);
+
+  EXPECT_EQ(obs.LastUsedBeginFrameArgs(),
+            MockBeginFrameObserver::kDefaultBeginFrameArgs);
+
+  // Used
+  obs.OnBeginFrame(
+      CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 100, 200, 300));
+  EXPECT_EQ(
+      obs.LastUsedBeginFrameArgs(),
+      CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 100, 200, 300));
+
+  // Dropped
+  obs.OnBeginFrame(
+      CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 400, 600, 300));
+  EXPECT_EQ(
+      obs.LastUsedBeginFrameArgs(),
+      CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 100, 200, 300));
+
+  // Dropped
+  obs.OnBeginFrame(
+      CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 450, 650, 300));
+  EXPECT_EQ(
+      obs.LastUsedBeginFrameArgs(),
+      CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 100, 200, 300));
+
+  // Used
+  obs.OnBeginFrame(
+      CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 700, 900, 300));
+  EXPECT_EQ(
+      obs.LastUsedBeginFrameArgs(),
+      CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 700, 900, 300));
+}
+
+}  // namespace
+}  // namespace cc
diff --git a/cc/test/layer_tree_host_common_test.cc b/cc/test/layer_tree_host_common_test.cc
index 676dc08..c05716df7 100644
--- a/cc/test/layer_tree_host_common_test.cc
+++ b/cc/test/layer_tree_host_common_test.cc
@@ -94,6 +94,10 @@
       root_layer->layer_tree_host()->inner_viewport_scroll_layer();
   Layer* outer_viewport_scroll_layer =
       root_layer->layer_tree_host()->outer_viewport_scroll_layer();
+  const Layer* overscroll_elasticity_layer =
+      root_layer->layer_tree_host()->overscroll_elasticity_layer();
+  gfx::Vector2dF elastic_overscroll =
+      root_layer->layer_tree_host()->elastic_overscroll();
   float page_scale_factor = 1.f;
   float device_scale_factor = 1.f;
   gfx::Size device_viewport_size =
@@ -101,7 +105,8 @@
                 root_layer->bounds().height() * device_scale_factor);
   BuildPropertyTreesAndComputeVisibleRects(
       root_layer, page_scale_layer, inner_viewport_scroll_layer,
-      outer_viewport_scroll_layer, page_scale_factor, device_scale_factor,
+      outer_viewport_scroll_layer, overscroll_elasticity_layer,
+      elastic_overscroll, page_scale_factor, device_scale_factor,
       gfx::Rect(device_viewport_size), identity_transform,
       can_render_to_separate_surface,
       root_layer->layer_tree_host()->property_trees(), &update_layer_list_);
@@ -119,6 +124,11 @@
       root_layer->layer_tree_impl()->InnerViewportScrollLayer();
   LayerImpl* outer_viewport_scroll_layer =
       root_layer->layer_tree_impl()->OuterViewportScrollLayer();
+  LayerImpl* overscroll_elasticity_layer =
+      root_layer->layer_tree_impl()->OverscrollElasticityLayer();
+  gfx::Vector2dF elastic_overscroll =
+      root_layer->layer_tree_impl()->elastic_overscroll()->Current(
+          root_layer->layer_tree_impl()->IsActiveTree());
   float page_scale_factor = 1.f;
   float device_scale_factor = 1.f;
   gfx::Size device_viewport_size =
@@ -127,7 +137,8 @@
   std::vector<LayerImpl*> update_layer_list;
   BuildPropertyTreesAndComputeVisibleRects(
       root_layer, page_scale_layer, inner_viewport_scroll_layer,
-      outer_viewport_scroll_layer, page_scale_factor, device_scale_factor,
+      outer_viewport_scroll_layer, overscroll_elasticity_layer,
+      elastic_overscroll, page_scale_factor, device_scale_factor,
       gfx::Rect(device_viewport_size), identity_transform,
       can_render_to_separate_surface,
       root_layer->layer_tree_impl()->property_trees(), &update_layer_list);
diff --git a/cc/test/mock_helper.h b/cc/test/mock_helper.h
new file mode 100644
index 0000000..9ca9afba
--- /dev/null
+++ b/cc/test/mock_helper.h
@@ -0,0 +1,29 @@
+// 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.
+
+#ifndef CC_TEST_MOCK_HELPER_H_
+#define CC_TEST_MOCK_HELPER_H_
+
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest-spi.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#define EXPECT_MOCK_FAILURE(statement)                            \
+  do {                                                            \
+    class GTestExpectMockFailureHelper {                          \
+     public:                                                      \
+      static void Execute() { statement; }                        \
+    };                                                            \
+    ::testing::TestPartResultArray gtest_failures;                \
+    {                                                             \
+      ::testing::ScopedFakeTestPartResultReporter gtest_reporter( \
+          ::testing::ScopedFakeTestPartResultReporter::           \
+              INTERCEPT_ONLY_CURRENT_THREAD,                      \
+          &gtest_failures);                                       \
+      GTestExpectMockFailureHelper::Execute();                    \
+    }                                                             \
+    EXPECT_GT(gtest_failures.size(), 0);                          \
+  } while (::testing::internal::AlwaysFalse())
+
+#endif  // CC_TEST_MOCK_HELPER_H_
diff --git a/cc/test/mock_helper_unittest.cc b/cc/test/mock_helper_unittest.cc
new file mode 100644
index 0000000..d6b9898
--- /dev/null
+++ b/cc/test/mock_helper_unittest.cc
@@ -0,0 +1,44 @@
+// 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.
+
+#include "cc/test/mock_helper.h"
+
+#include "testing/gtest/include/gtest/gtest-spi.h"
+
+namespace {
+class TestingMock {
+ public:
+  MOCK_METHOD0(Test, void(void));
+};
+
+TEST(ExpectMockFailureTest, FailsWhenNoMock) {
+  EXPECT_NONFATAL_FAILURE({ EXPECT_MOCK_FAILURE({ ; }); }, "");
+}
+
+TEST(ExpectMockFailureTest, FailsWhenMockSucceeds) {
+  EXPECT_NONFATAL_FAILURE({
+    EXPECT_MOCK_FAILURE({
+      ::testing::NiceMock<TestingMock> t1;
+      EXPECT_CALL(t1, Test());
+
+      t1.Test();
+    });
+  }, "");
+}
+
+TEST(ExpectMockFailureTest, PassesWhenMockFailsForMissing) {
+  EXPECT_MOCK_FAILURE({
+    ::testing::NiceMock<TestingMock> t1;
+    EXPECT_CALL(t1, Test());
+  });
+}
+
+TEST(ExpectMockFailureTest, PassesWhenMockFailsForUnexpected) {
+  EXPECT_MOCK_FAILURE({
+    ::testing::StrictMock<TestingMock> t1;
+    t1.Test();
+  });
+}
+
+}  // namespace
diff --git a/cc/tiles/tile_manager_unittest.cc b/cc/tiles/tile_manager_unittest.cc
index 795118f..2c69999b 100644
--- a/cc/tiles/tile_manager_unittest.cc
+++ b/cc/tiles/tile_manager_unittest.cc
@@ -1730,7 +1730,7 @@
     // Just call CompleteOnOriginThread on each item in the queue. As none of
     // these items have run yet, they will be treated as cancelled tasks.
     for (const auto& node : graph->nodes) {
-      static_cast<RasterTask*>(node.task)->CompleteOnOriginThread(this);
+      static_cast<TileTask*>(node.task)->CompleteOnOriginThread(this);
     }
   }
 };
@@ -1805,7 +1805,7 @@
 
   void ScheduleTasks(TaskGraph* graph) override {
     for (const auto& node : graph->nodes) {
-      RasterTask* task = static_cast<RasterTask*>(node.task);
+      TileTask* task = static_cast<TileTask*>(node.task);
       // Triggers a call to AcquireBufferForRaster.
       task->ScheduleOnOriginThread(this);
       // Calls TileManager as though task was cancelled.
diff --git a/cc/trees/draw_property_utils.cc b/cc/trees/draw_property_utils.cc
index 326e507..971888dc 100644
--- a/cc/trees/draw_property_utils.cc
+++ b/cc/trees/draw_property_utils.cc
@@ -634,6 +634,8 @@
     const Layer* page_scale_layer,
     const Layer* inner_viewport_scroll_layer,
     const Layer* outer_viewport_scroll_layer,
+    const Layer* overscroll_elasticity_layer,
+    const gfx::Vector2dF& elastic_overscroll,
     float page_scale_factor,
     float device_scale_factor,
     const gfx::Rect& viewport,
@@ -643,8 +645,9 @@
     LayerList* update_layer_list) {
   PropertyTreeBuilder::BuildPropertyTrees(
       root_layer, page_scale_layer, inner_viewport_scroll_layer,
-      outer_viewport_scroll_layer, page_scale_factor, device_scale_factor,
-      viewport, device_transform, property_trees);
+      outer_viewport_scroll_layer, overscroll_elasticity_layer,
+      elastic_overscroll, page_scale_factor, device_scale_factor, viewport,
+      device_transform, property_trees);
   ComputeVisibleRectsUsingPropertyTrees(root_layer, property_trees,
                                         can_render_to_separate_surface,
                                         update_layer_list);
@@ -655,6 +658,8 @@
     const LayerImpl* page_scale_layer,
     const LayerImpl* inner_viewport_scroll_layer,
     const LayerImpl* outer_viewport_scroll_layer,
+    const LayerImpl* overscroll_elasticity_layer,
+    const gfx::Vector2dF& elastic_overscroll,
     float page_scale_factor,
     float device_scale_factor,
     const gfx::Rect& viewport,
@@ -664,8 +669,9 @@
     LayerImplList* visible_layer_list) {
   PropertyTreeBuilder::BuildPropertyTrees(
       root_layer, page_scale_layer, inner_viewport_scroll_layer,
-      outer_viewport_scroll_layer, page_scale_factor, device_scale_factor,
-      viewport, device_transform, property_trees);
+      outer_viewport_scroll_layer, overscroll_elasticity_layer,
+      elastic_overscroll, page_scale_factor, device_scale_factor, viewport,
+      device_transform, property_trees);
   ComputeVisibleRectsUsingPropertyTrees(root_layer, property_trees,
                                         can_render_to_separate_surface,
                                         visible_layer_list);
@@ -1077,4 +1083,40 @@
       device_transform);
 }
 
+template <typename LayerType>
+static void UpdateElasticOverscrollInPropertyTreesInternal(
+    PropertyTrees* property_trees,
+    const LayerType* overscroll_elasticity_layer,
+    const gfx::Vector2dF& elastic_overscroll) {
+  if (!overscroll_elasticity_layer) {
+    DCHECK(elastic_overscroll.IsZero());
+    return;
+  }
+
+  TransformNode* node = property_trees->transform_tree.Node(
+      overscroll_elasticity_layer->transform_tree_index());
+  if (node->data.scroll_offset == gfx::ScrollOffset(elastic_overscroll))
+    return;
+
+  node->data.scroll_offset = gfx::ScrollOffset(elastic_overscroll);
+  node->data.needs_local_transform_update = true;
+  property_trees->transform_tree.set_needs_update(true);
+}
+
+void UpdateElasticOverscrollInPropertyTrees(
+    PropertyTrees* property_trees,
+    const LayerImpl* overscroll_elasticity_layer,
+    const gfx::Vector2dF& elastic_overscroll) {
+  UpdateElasticOverscrollInPropertyTreesInternal(
+      property_trees, overscroll_elasticity_layer, elastic_overscroll);
+}
+
+void UpdateElasticOverscrollInPropertyTrees(
+    PropertyTrees* property_trees,
+    const Layer* overscroll_elasticity_layer,
+    const gfx::Vector2dF& elastic_overscroll) {
+  UpdateElasticOverscrollInPropertyTreesInternal(
+      property_trees, overscroll_elasticity_layer, elastic_overscroll);
+}
+
 }  // namespace cc
diff --git a/cc/trees/draw_property_utils.h b/cc/trees/draw_property_utils.h
index 5c99458..72d9337 100644
--- a/cc/trees/draw_property_utils.h
+++ b/cc/trees/draw_property_utils.h
@@ -11,6 +11,7 @@
 namespace gfx {
 class Rect;
 class Transform;
+class Vector2dF;
 }  // namespace gfx
 
 namespace cc {
@@ -46,6 +47,8 @@
     const Layer* page_scale_layer,
     const Layer* inner_viewport_scroll_layer,
     const Layer* outer_viewport_scroll_layer,
+    const Layer* overscroll_elasticity_layer,
+    const gfx::Vector2dF& elastic_overscroll,
     float page_scale_factor,
     float device_scale_factor,
     const gfx::Rect& viewport,
@@ -59,6 +62,8 @@
     const LayerImpl* page_scale_layer,
     const LayerImpl* inner_viewport_scroll_layer,
     const LayerImpl* outer_viewport_scroll_layer,
+    const LayerImpl* overscroll_elasticity_layer,
+    const gfx::Vector2dF& elastic_overscroll,
     float page_scale_factor,
     float device_scale_factor,
     const gfx::Rect& viewport,
@@ -123,6 +128,17 @@
                                      float page_scale_factor,
                                      float device_scale_factor,
                                      const gfx::Transform device_transform);
+
+void CC_EXPORT UpdateElasticOverscrollInPropertyTrees(
+    PropertyTrees* property_trees,
+    const LayerImpl* overscroll_elasticity_layer,
+    const gfx::Vector2dF& elastic_overscroll);
+
+void CC_EXPORT UpdateElasticOverscrollInPropertyTrees(
+    PropertyTrees* property_trees,
+    const Layer* overscroll_elasticity_layer,
+    const gfx::Vector2dF& elastic_overscroll);
+
 }  // namespace cc
 
 #endif  // CC_TREES_DRAW_PROPERTY_UTILS_H_
diff --git a/cc/trees/layer_tree_host.cc b/cc/trees/layer_tree_host.cc
index 338bb36..4152b4d 100644
--- a/cc/trees/layer_tree_host.cc
+++ b/cc/trees/layer_tree_host.cc
@@ -795,10 +795,10 @@
                  "LayerTreeHostCommon::ComputeVisibleRectsWithPropertyTrees");
     BuildPropertyTreesAndComputeVisibleRects(
         root_layer, page_scale_layer, inner_viewport_scroll_layer_.get(),
-        outer_viewport_scroll_layer_.get(), page_scale_factor_,
-        device_scale_factor_, gfx::Rect(device_viewport_size_),
-        identity_transform, can_render_to_separate_surface, &property_trees_,
-        &update_layer_list);
+        outer_viewport_scroll_layer_.get(), overscroll_elasticity_layer_.get(),
+        elastic_overscroll_, page_scale_factor_, device_scale_factor_,
+        gfx::Rect(device_viewport_size_), identity_transform,
+        can_render_to_separate_surface, &property_trees_, &update_layer_list);
   }
 
   for (const auto& layer : update_layer_list)
diff --git a/cc/trees/layer_tree_host_common.cc b/cc/trees/layer_tree_host_common.cc
index 172b01e..9ab91f03 100644
--- a/cc/trees/layer_tree_host_common.cc
+++ b/cc/trees/layer_tree_host_common.cc
@@ -2766,7 +2766,9 @@
         BuildPropertyTreesAndComputeVisibleRects(
             inputs->root_layer, inputs->page_scale_layer,
             inputs->inner_viewport_scroll_layer,
-            inputs->outer_viewport_scroll_layer, inputs->page_scale_factor,
+            inputs->outer_viewport_scroll_layer,
+            inputs->elastic_overscroll_application_layer,
+            inputs->elastic_overscroll, inputs->page_scale_factor,
             inputs->device_scale_factor,
             gfx::Rect(inputs->device_viewport_size), inputs->device_transform,
             inputs->can_render_to_separate_surface, inputs->property_trees,
@@ -2791,14 +2793,18 @@
         TRACE_EVENT0(
             TRACE_DISABLED_BY_DEFAULT("cc.debug.cdp-perf"),
             "LayerTreeHostCommon::ComputeJustVisibleRectsWithPropertyTrees");
-        // Since page scale is a SyncedProperty, changes to page scale on the
-        // active tree immediately affect the pending tree, so instead of
-        // trying to update property trees whenever page scale changes, we
-        // update their page scale before using them.
+        // Since page scale and elastic overscroll are SyncedProperties, changes
+        // on the active tree immediately affect the pending tree, so instead of
+        // trying to update property trees whenever these values change, we
+        // update property trees before using them.
         UpdatePageScaleFactorInPropertyTrees(
             inputs->property_trees, inputs->page_scale_layer,
             inputs->page_scale_factor, inputs->device_scale_factor,
             inputs->device_transform);
+        UpdateElasticOverscrollInPropertyTrees(
+            inputs->property_trees,
+            inputs->elastic_overscroll_application_layer,
+            inputs->elastic_overscroll);
         // Similarly, the device viewport and device transform are shared
         // by both trees.
         inputs->property_trees->clip_tree.SetViewportClip(
@@ -2866,9 +2872,12 @@
                        gfx::Transform(), false);
   PropertyTrees* property_trees =
       inputs->root_layer->layer_tree_host()->property_trees();
+  Layer* overscroll_elasticity_layer = nullptr;
+  gfx::Vector2dF elastic_overscroll;
   BuildPropertyTreesAndComputeVisibleRects(
       inputs->root_layer, inputs->page_scale_layer,
       inputs->inner_viewport_scroll_layer, inputs->outer_viewport_scroll_layer,
+      overscroll_elasticity_layer, elastic_overscroll,
       inputs->page_scale_factor, inputs->device_scale_factor,
       gfx::Rect(inputs->device_viewport_size), inputs->device_transform,
       can_render_to_separate_surface, property_trees, &update_layer_list);
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index fdf32f0..4ab2028 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -1070,6 +1070,14 @@
   // trigger this DCHECK.
   DCHECK(!have_copy_request || draw_result == DRAW_SUCCESS);
 
+  // TODO(crbug.com/564832): This workaround to prevent creating unnecessarily
+  // persistent render passes. When a copy request is made, it may force a
+  // separate render pass for the layer, which will persist until a new commit
+  // removes it. Force a commit after copy requests, to remove extra render
+  // passes.
+  if (have_copy_request)
+    client_->SetNeedsCommitOnImplThread();
+
   return draw_result;
 }
 
diff --git a/cc/trees/layer_tree_host_unittest.cc b/cc/trees/layer_tree_host_unittest.cc
index 152b873..a68cb02 100644
--- a/cc/trees/layer_tree_host_unittest.cc
+++ b/cc/trees/layer_tree_host_unittest.cc
@@ -13,6 +13,7 @@
 #include "base/thread_task_runner_handle.h"
 #include "cc/animation/timing_function.h"
 #include "cc/debug/frame_rate_counter.h"
+#include "cc/input/scroll_elasticity_helper.h"
 #include "cc/layers/content_layer_client.h"
 #include "cc/layers/io_surface_layer.h"
 #include "cc/layers/layer_impl.h"
@@ -3846,6 +3847,105 @@
 
 MULTI_THREAD_TEST_F(LayerTreeHostTestUpdateLayerInEmptyViewport);
 
+class LayerTreeHostTestElasticOverscroll : public LayerTreeHostTest {
+ public:
+  LayerTreeHostTestElasticOverscroll()
+      : scroll_elasticity_helper_(nullptr), num_draws_(0) {}
+
+  void InitializeSettings(LayerTreeSettings* settings) override {
+    settings->enable_elastic_overscroll = true;
+  }
+
+  void SetupTree() override {
+    root_layer_ = Layer::Create(layer_settings());
+    root_layer_->SetBounds(gfx::Size(10, 10));
+
+    scoped_refptr<Layer> inner_viewport_container_layer =
+        Layer::Create(layer_settings());
+    inner_viewport_container_layer->SetBounds(gfx::Size(10, 10));
+    scoped_refptr<Layer> overscroll_elasticity_layer =
+        Layer::Create(layer_settings());
+    scoped_refptr<Layer> page_scale_layer = Layer::Create(layer_settings());
+    scoped_refptr<Layer> inner_viewport_scroll_layer =
+        Layer::Create(layer_settings());
+    inner_viewport_scroll_layer->SetScrollClipLayerId(
+        inner_viewport_container_layer->id());
+    inner_viewport_scroll_layer->SetIsContainerForFixedPositionLayers(true);
+
+    root_layer_->AddChild(inner_viewport_container_layer);
+    inner_viewport_container_layer->AddChild(overscroll_elasticity_layer);
+    overscroll_elasticity_layer->AddChild(page_scale_layer);
+    page_scale_layer->AddChild(inner_viewport_scroll_layer);
+
+    scoped_refptr<Layer> content_layer =
+        FakePictureLayer::Create(layer_settings(), &client_);
+    content_layer->SetBounds(gfx::Size(10, 10));
+    inner_viewport_scroll_layer->AddChild(content_layer);
+
+    layer_tree_host()->SetRootLayer(root_layer_);
+    layer_tree_host()->RegisterViewportLayers(
+        overscroll_elasticity_layer, page_scale_layer,
+        inner_viewport_scroll_layer, nullptr);
+    LayerTreeHostTest::SetupTree();
+    client_.set_bounds(content_layer->bounds());
+  }
+
+  void BeginTest() override { PostSetNeedsCommitToMainThread(); }
+
+  void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) override {
+    if (host_impl->sync_tree()->source_frame_number() == 0) {
+      scroll_elasticity_helper_ = host_impl->CreateScrollElasticityHelper();
+    }
+  }
+
+  void DrawLayersOnThread(LayerTreeHostImpl* host_impl) override {
+    num_draws_++;
+    LayerImpl* content_layer_impl = host_impl->active_tree()
+                                        ->InnerViewportScrollLayer()
+                                        ->children()[0]
+                                        .get();
+    gfx::Transform expected_draw_transform;
+    switch (num_draws_) {
+      case 1:
+        // Initially, there's no overscroll.
+        EXPECT_EQ(expected_draw_transform, content_layer_impl->DrawTransform());
+
+        // Begin overscrolling. This should be reflected in the draw transform
+        // the next time we draw.
+        scroll_elasticity_helper_->SetStretchAmount(gfx::Vector2dF(5.f, 6.f));
+        break;
+      case 2:
+        expected_draw_transform.Translate(-5.0, -6.0);
+        EXPECT_EQ(expected_draw_transform, content_layer_impl->DrawTransform());
+
+        scroll_elasticity_helper_->SetStretchAmount(gfx::Vector2dF(3.f, 2.f));
+        break;
+      case 3:
+        expected_draw_transform.Translate(-3.0, -2.0);
+        EXPECT_EQ(expected_draw_transform, content_layer_impl->DrawTransform());
+
+        scroll_elasticity_helper_->SetStretchAmount(gfx::Vector2dF());
+        break;
+      case 4:
+        EXPECT_EQ(expected_draw_transform, content_layer_impl->DrawTransform());
+        EndTest();
+        break;
+      default:
+        NOTREACHED();
+    }
+  }
+
+  void AfterTest() override {}
+
+ private:
+  FakeContentLayerClient client_;
+  scoped_refptr<Layer> root_layer_;
+  ScrollElasticityHelper* scroll_elasticity_helper_;
+  int num_draws_;
+};
+
+MULTI_THREAD_TEST_F(LayerTreeHostTestElasticOverscroll);
+
 class LayerTreeHostTestSetMemoryPolicyOnLostOutputSurface
     : public LayerTreeHostTest {
  protected:
diff --git a/cc/trees/layer_tree_host_unittest_copyrequest.cc b/cc/trees/layer_tree_host_unittest_copyrequest.cc
index 86c7dc28..c2171a96 100644
--- a/cc/trees/layer_tree_host_unittest_copyrequest.cc
+++ b/cc/trees/layer_tree_host_unittest_copyrequest.cc
@@ -41,7 +41,7 @@
 
   void BeginTest() override { PostSetNeedsCommitToMainThread(); }
 
-  void DidCommitAndDrawFrame() override { WaitForCallback(); }
+  void DidCommit() override { WaitForCallback(); }
 
   void WaitForCallback() {
     base::MessageLoop::current()->PostTask(
@@ -61,6 +61,9 @@
         EXPECT_EQ(0u, callbacks_.size());
         break;
       case 2:
+        // This commit is triggered by the copy request having been completed.
+        break;
+      case 3:
         if (callbacks_.size() < 1u) {
           WaitForCallback();
           return;
@@ -82,7 +85,10 @@
                        base::Unretained(this), 3)));
         EXPECT_EQ(1u, callbacks_.size());
         break;
-      case 3:
+      case 4:
+        // This commit is triggered by the copy request having been completed.
+        break;
+      case 5:
         if (callbacks_.size() < 4u) {
           WaitForCallback();
           return;
@@ -175,6 +181,66 @@
   RunTest(true, false);
 }
 
+// TODO(crbug.com/564832): Remove this test when the workaround it tests is no
+// longer needed.
+class LayerTreeHostCopyRequestCompletionCausesCommit
+    : public LayerTreeHostCopyRequestTest {
+ protected:
+  void SetupTree() override {
+    root_ = FakePictureLayer::Create(layer_settings(), &client_);
+    root_->SetBounds(gfx::Size(20, 20));
+
+    layer_ = FakePictureLayer::Create(layer_settings(), &client_);
+    layer_->SetBounds(gfx::Size(15, 15));
+    root_->AddChild(layer_);
+
+    layer_tree_host()->SetRootLayer(root_);
+    LayerTreeHostCopyRequestTest::SetupTree();
+    client_.set_bounds(root_->bounds());
+  }
+
+  void BeginTest() override {
+    callback_count_ = 0;
+    PostSetNeedsCommitToMainThread();
+  }
+
+  void DidCommit() override {
+    int frame = layer_tree_host()->source_frame_number();
+    switch (frame) {
+      case 1:
+        layer_->RequestCopyOfOutput(CopyOutputRequest::CreateBitmapRequest(
+            base::Bind(&LayerTreeHostCopyRequestCompletionCausesCommit::
+                           CopyOutputCallback,
+                       base::Unretained(this))));
+        EXPECT_EQ(0, callback_count_);
+        break;
+      case 2:
+        // This commit was triggered by the copy request.
+        break;
+      case 3:
+        // This commit was triggered by the completion of the copy request.
+        EXPECT_EQ(1, callback_count_);
+        EndTest();
+        break;
+    }
+  }
+
+  void CopyOutputCallback(scoped_ptr<CopyOutputResult> result) {
+    EXPECT_FALSE(result->IsEmpty());
+    ++callback_count_;
+  }
+
+  void AfterTest() override {}
+
+  int callback_count_;
+  FakeContentLayerClient client_;
+  scoped_refptr<FakePictureLayer> root_;
+  scoped_refptr<FakePictureLayer> layer_;
+};
+
+SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_TEST_F(
+    LayerTreeHostCopyRequestCompletionCausesCommit);
+
 class LayerTreeHostCopyRequestTestLayerDestroyed
     : public LayerTreeHostCopyRequestTest {
  protected:
@@ -427,8 +493,14 @@
 
     // |copy_layer| should have been rendered to a texture since it was needed
     // for a copy request.
-    EXPECT_TRUE(renderer->HasAllocatedResourcesForTesting(
-        copy_layer->render_surface()->GetRenderPassId()));
+    if (did_draw_) {
+      // TODO(crbug.com/564832): Ignore the extra frame that occurs due to copy
+      // completion. This can be removed when the extra commit is removed.
+      EXPECT_FALSE(copy_layer->render_surface());
+    } else {
+      EXPECT_TRUE(renderer->HasAllocatedResourcesForTesting(
+          copy_layer->render_surface()->GetRenderPassId()));
+    }
 
     did_draw_ = true;
   }
@@ -795,7 +867,7 @@
 
   virtual void RequestCopy(Layer* layer) = 0;
 
-  void DidCommitAndDrawFrame() override {
+  void DidCommit() override {
     switch (layer_tree_host()->source_frame_number()) {
       case 1:
         // The layers have been pushed to the impl side. The layer textures have
@@ -1100,7 +1172,7 @@
     PostSetNeedsCommitToMainThread();
   }
 
-  void DidCommitAndDrawFrame() override {
+  void DidCommit() override {
     // Send a copy request after the first commit.
     if (layer_tree_host()->source_frame_number() == 1) {
       child_->RequestCopyOfOutput(
diff --git a/cc/trees/layer_tree_impl.cc b/cc/trees/layer_tree_impl.cc
index 02583d2..f7fee78 100644
--- a/cc/trees/layer_tree_impl.cc
+++ b/cc/trees/layer_tree_impl.cc
@@ -789,9 +789,11 @@
   LayerTreeHostCommon::PreCalculateMetaInformationForTesting(root_layer_.get());
   PropertyTreeBuilder::BuildPropertyTrees(
       root_layer_.get(), PageScaleLayer(), InnerViewportScrollLayer(),
-      OuterViewportScrollLayer(), current_page_scale_factor(),
-      device_scale_factor(), gfx::Rect(DrawViewportSize()),
-      layer_tree_host_impl_->DrawTransform(), &property_trees_);
+      OuterViewportScrollLayer(), OverscrollElasticityLayer(),
+      elastic_overscroll()->Current(IsActiveTree()),
+      current_page_scale_factor(), device_scale_factor(),
+      gfx::Rect(DrawViewportSize()), layer_tree_host_impl_->DrawTransform(),
+      &property_trees_);
 }
 
 void LayerTreeImpl::IncrementRenderSurfaceListIdForTesting() {
diff --git a/cc/trees/property_tree_builder.cc b/cc/trees/property_tree_builder.cc
index 8bdf7e4..8763b91 100644
--- a/cc/trees/property_tree_builder.cc
+++ b/cc/trees/property_tree_builder.cc
@@ -37,6 +37,8 @@
   const LayerType* page_scale_layer;
   const LayerType* inner_viewport_scroll_layer;
   const LayerType* outer_viewport_scroll_layer;
+  const LayerType* overscroll_elasticity_layer;
+  gfx::Vector2dF elastic_overscroll;
   float page_scale_factor;
   bool in_subtree_of_page_scale_layer;
   bool affected_by_inner_viewport_bounds_delta;
@@ -213,6 +215,8 @@
     DataForRecursion<LayerType>* data_for_children) {
   const bool is_root = !layer->parent();
   const bool is_page_scale_layer = layer == data_from_ancestor.page_scale_layer;
+  const bool is_overscroll_elasticity_layer =
+      layer == data_from_ancestor.overscroll_elasticity_layer;
   const bool is_scrollable = layer->scrollable();
   const bool is_fixed = layer->position_constraint().is_fixed_position();
 
@@ -233,7 +237,7 @@
 
   bool requires_node = is_root || is_scrollable || has_significant_transform ||
                        has_any_transform_animation || has_surface || is_fixed ||
-                       is_page_scale_layer;
+                       is_page_scale_layer || is_overscroll_elasticity_layer;
 
   LayerType* transform_parent = GetTransformParent(data_from_ancestor, layer);
   DCHECK(is_root || transform_parent);
@@ -365,8 +369,13 @@
                                            layer->transform_origin());
   }
 
-  if (!layer->scroll_parent())
+  if (is_overscroll_elasticity_layer) {
+    DCHECK(!is_scrollable);
+    node->data.scroll_offset =
+        gfx::ScrollOffset(data_from_ancestor.elastic_overscroll);
+  } else if (!layer->scroll_parent()) {
     node->data.scroll_offset = layer->CurrentScrollOffset();
+  }
 
   if (is_fixed) {
     if (data_from_ancestor.affected_by_inner_viewport_bounds_delta) {
@@ -526,6 +535,8 @@
     const LayerType* page_scale_layer,
     const LayerType* inner_viewport_scroll_layer,
     const LayerType* outer_viewport_scroll_layer,
+    const LayerType* overscroll_elasticity_layer,
+    const gfx::Vector2dF& elastic_overscroll,
     float page_scale_factor,
     float device_scale_factor,
     const gfx::Rect& viewport,
@@ -535,6 +546,8 @@
     UpdatePageScaleFactorInPropertyTrees(property_trees, page_scale_layer,
                                          page_scale_factor, device_scale_factor,
                                          device_transform);
+    UpdateElasticOverscrollInPropertyTrees(
+        property_trees, overscroll_elasticity_layer, elastic_overscroll);
     property_trees->clip_tree.SetViewportClip(gfx::RectF(viewport));
     property_trees->transform_tree.SetDeviceTransform(device_transform,
                                                       root_layer->position());
@@ -555,6 +568,8 @@
   data_for_recursion.page_scale_layer = page_scale_layer;
   data_for_recursion.inner_viewport_scroll_layer = inner_viewport_scroll_layer;
   data_for_recursion.outer_viewport_scroll_layer = outer_viewport_scroll_layer;
+  data_for_recursion.overscroll_elasticity_layer = overscroll_elasticity_layer;
+  data_for_recursion.elastic_overscroll = elastic_overscroll;
   data_for_recursion.page_scale_factor = page_scale_factor;
   data_for_recursion.in_subtree_of_page_scale_layer = false;
   data_for_recursion.affected_by_inner_viewport_bounds_delta = false;
@@ -593,6 +608,8 @@
     const Layer* page_scale_layer,
     const Layer* inner_viewport_scroll_layer,
     const Layer* outer_viewport_scroll_layer,
+    const Layer* overscroll_elasticity_layer,
+    const gfx::Vector2dF& elastic_overscroll,
     float page_scale_factor,
     float device_scale_factor,
     const gfx::Rect& viewport,
@@ -600,8 +617,9 @@
     PropertyTrees* property_trees) {
   BuildPropertyTreesTopLevelInternal(
       root_layer, page_scale_layer, inner_viewport_scroll_layer,
-      outer_viewport_scroll_layer, page_scale_factor, device_scale_factor,
-      viewport, device_transform, property_trees);
+      outer_viewport_scroll_layer, overscroll_elasticity_layer,
+      elastic_overscroll, page_scale_factor, device_scale_factor, viewport,
+      device_transform, property_trees);
 }
 
 void PropertyTreeBuilder::BuildPropertyTrees(
@@ -609,6 +627,8 @@
     const LayerImpl* page_scale_layer,
     const LayerImpl* inner_viewport_scroll_layer,
     const LayerImpl* outer_viewport_scroll_layer,
+    const LayerImpl* overscroll_elasticity_layer,
+    const gfx::Vector2dF& elastic_overscroll,
     float page_scale_factor,
     float device_scale_factor,
     const gfx::Rect& viewport,
@@ -616,8 +636,9 @@
     PropertyTrees* property_trees) {
   BuildPropertyTreesTopLevelInternal(
       root_layer, page_scale_layer, inner_viewport_scroll_layer,
-      outer_viewport_scroll_layer, page_scale_factor, device_scale_factor,
-      viewport, device_transform, property_trees);
+      outer_viewport_scroll_layer, overscroll_elasticity_layer,
+      elastic_overscroll, page_scale_factor, device_scale_factor, viewport,
+      device_transform, property_trees);
 }
 
 }  // namespace cc
diff --git a/cc/trees/property_tree_builder.h b/cc/trees/property_tree_builder.h
index a6cc52b4..23d7e1c 100644
--- a/cc/trees/property_tree_builder.h
+++ b/cc/trees/property_tree_builder.h
@@ -20,6 +20,8 @@
                                  const Layer* page_scale_layer,
                                  const Layer* inner_viewport_scroll_layer,
                                  const Layer* outer_viewport_scroll_layer,
+                                 const Layer* overscroll_elasticity_layer,
+                                 const gfx::Vector2dF& elastic_overscroll,
                                  float page_scale_factor,
                                  float device_scale_factor,
                                  const gfx::Rect& viewport,
@@ -29,6 +31,8 @@
                                  const LayerImpl* page_scale_layer,
                                  const LayerImpl* inner_viewport_scroll_layer,
                                  const LayerImpl* outer_viewport_scroll_layer,
+                                 const LayerImpl* overscroll_elasticity_layer,
+                                 const gfx::Vector2dF& elastic_overscroll,
                                  float page_scale_factor,
                                  float device_scale_factor,
                                  const gfx::Rect& viewport,
diff --git a/chrome/BUILD.gn b/chrome/BUILD.gn
index efb7dc6..462e318 100644
--- a/chrome/BUILD.gn
+++ b/chrome/BUILD.gn
@@ -405,8 +405,6 @@
 
     shared_library("chrome_child") {
       sources = [
-        "app/chrome_crash_reporter_client.cc",
-        "app/chrome_crash_reporter_client.h",
         "app/chrome_main.cc",
         "app/chrome_main_delegate.cc",
         "app/chrome_main_delegate.h",
diff --git a/chrome/VERSION b/chrome/VERSION
index b2e8716..38e2fd6 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=49
 MINOR=0
-BUILD=2581
+BUILD=2584
 PATCH=0
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index 9de720c9..3ae8926 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -6,6 +6,7 @@
 import("//build/config/android/rules.gni")
 import("//build_overrides/v8.gni")
 import("//chrome/android/chrome_public_apk_tmpl.gni")
+import("//chrome/common/features.gni")
 import("//chrome/version.gni")
 import("//testing/test.gni")
 import("//third_party/icu/config.gni")
@@ -128,29 +129,14 @@
 # GYP: //chrome/chrome.gyp:chrome_java
 android_library("chrome_java") {
   deps = [
-    ":chrome_java_resources",
-    ":document_tab_model_info_proto_java",
     "//base:base_java",
-    "//components/bookmarks/common/android:bookmarks_java",
-    "//components/dom_distiller/android:dom_distiller_content_java",
-    "//components/dom_distiller/android:dom_distiller_core_java",
-    "//components/gcm_driver/android:gcm_driver_java",
-    "//components/invalidation/impl:java",
-    "//components/navigation_interception/android:navigation_interception_java",
-    "//components/policy/android:policy_java",
-    "//components/precache/android:precache_java",
     "//components/safe_json/android:safe_json_java",
-    "//components/service_tab_launcher:service_tab_launcher_java",
-    "//components/signin/core/browser/android:java",
     "//components/variations/android:variations_java",
-    "//components/web_contents_delegate_android:web_contents_delegate_android_java",
     "//content/public/android:content_java",
     "//media/base/android:media_java",
-    "//media/base/android:media_java",
     "//media/midi:midi_java",
     "//net/android:net_java",
     "//printing:printing_java",
-    "//sync/android:sync_java",
     "//third_party/WebKit/public:blink_headers_java",
     "//third_party/android_data_chart:android_data_chart_java",
     "//third_party/android_media:android_media_java",
@@ -175,17 +161,41 @@
     ":chrome_android_java_enums_srcjar",
     ":chrome_android_java_google_api_keys_srcjar",
     ":chrome_version_srcjar",
-    ":custom_tabs_service_aidl",
     ":resource_id_javagen",
-    "//chrome:page_info_connection_type_javagen",
     "//chrome:content_setting_javagen",
     "//chrome:content_settings_type_javagen",
-    "//components/enhanced_bookmarks:enhanced_bookmarks_java_enums_srcjar",
-    "//components/offline_pages:offline_pages_enums_java",
-    "//components/omnibox/browser:autocomplete_match_type_javagen",
   ]
 
-  DEPRECATED_java_in_dir = "java/src"
+  # TODO(sievers): Split java code into components. Not everything
+  # is really all that UI related here.
+  if (android_java_ui) {
+    DEPRECATED_java_in_dir = "java/src"
+
+    srcjar_deps += [
+      ":custom_tabs_service_aidl",
+      "//chrome:page_info_connection_type_javagen",
+      "//components/enhanced_bookmarks:enhanced_bookmarks_java_enums_srcjar",
+      "//components/offline_pages:offline_pages_enums_java",
+      "//components/omnibox/browser:autocomplete_match_type_javagen",
+    ]
+
+    deps += [
+      ":chrome_java_resources",
+      ":document_tab_model_info_proto_java",
+      "//components/bookmarks/common/android:bookmarks_java",
+      "//components/dom_distiller/android:dom_distiller_content_java",
+      "//components/dom_distiller/android:dom_distiller_core_java",
+      "//components/gcm_driver/android:gcm_driver_java",
+      "//components/invalidation/impl:java",
+      "//components/navigation_interception/android:navigation_interception_java",
+      "//components/policy/android:policy_java",
+      "//components/precache/android:precache_java",
+      "//components/service_tab_launcher:service_tab_launcher_java",
+      "//components/signin/core/browser/android:java",
+      "//components/web_contents_delegate_android:web_contents_delegate_android_java",
+      "//sync/android:sync_java",
+    ]
+  }
 }
 
 # GYP: //chrome/chrome_browser.gypi:activity_type_ids_java
diff --git a/chrome/android/chrome_apk_version.gni b/chrome/android/chrome_apk_version.gni
new file mode 100644
index 0000000..98401aa
--- /dev/null
+++ b/chrome/android/chrome_apk_version.gni
@@ -0,0 +1,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.
+
+declare_args() {
+  chrome_apk_version_code = "1"
+  chrome_apk_version_name = "Developer Build"
+}
diff --git a/chrome/android/java/res/drawable/most_visited_item_bg.xml b/chrome/android/java/res/drawable/most_visited_item_bg.xml
deleted file mode 100644
index 1799b6ff..0000000
--- a/chrome/android/java/res/drawable/most_visited_item_bg.xml
+++ /dev/null
@@ -1,10 +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. -->
-
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
-    android:shape="rectangle">
-    <solid android:color="@color/ntp_most_visited_bg" />
-    <corners android:radius="@dimen/most_visited_bg_corner_radius" />
-</shape>
diff --git a/chrome/android/java/res/drawable/most_visited_item_empty.xml b/chrome/android/java/res/drawable/most_visited_item_empty.xml
deleted file mode 100644
index 3b9555c7..0000000
--- a/chrome/android/java/res/drawable/most_visited_item_empty.xml
+++ /dev/null
@@ -1,28 +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. -->
-
-<!-- A blank most visited item, for display on the new tab page. -->
-<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
-
-    <item>
-        <shape android:shape="rectangle">
-            <solid android:color="@color/ntp_most_visited_bg" />
-            <corners android:radius="@dimen/most_visited_bg_corner_radius" />
-        </shape>
-    </item>
-
-    <item>
-        <inset
-            android:insetTop="4dp"
-            android:insetRight="4dp"
-            android:insetBottom="4dp"
-            android:insetLeft="4dp">
-            <shape android:shape="rectangle">
-                <solid android:color="#fff" />
-            </shape>
-        </inset>
-    </item>
-
-</layer-list>
diff --git a/chrome/android/java/res/drawable/most_visited_thumbnail_placeholder.xml b/chrome/android/java/res/drawable/most_visited_thumbnail_placeholder.xml
deleted file mode 100644
index 3e065a74..0000000
--- a/chrome/android/java/res/drawable/most_visited_thumbnail_placeholder.xml
+++ /dev/null
@@ -1,11 +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. -->
-
-<!-- The circle in the middle of a most visited item that has no thumbnail. -->
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
-    android:shape="oval">
-    <solid android:color="@color/ntp_most_visited_bg" />
-    <size android:width="27dp" android:height="27dp" />
-</shape>
\ No newline at end of file
diff --git a/chrome/android/java/res/layout/most_visited_item.xml b/chrome/android/java/res/layout/most_visited_item.xml
deleted file mode 100644
index de02755..0000000
--- a/chrome/android/java/res/layout/most_visited_item.xml
+++ /dev/null
@@ -1,44 +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. -->
-
-<!-- A most visited item, for display on the new tab page. -->
-<org.chromium.chrome.browser.ntp.MostVisitedItemView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="@dimen/most_visited_tile_width"
-    android:layout_height="130dp" >
-
-    <LinearLayout
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:background="@drawable/most_visited_item_bg"
-        android:orientation="vertical"
-        android:padding="4dp" >
-        <TextView
-            android:id="@+id/most_visited_title"
-            android:layout_width="match_parent"
-            android:layout_height="24dp"
-            android:layout_marginBottom="4dp"
-            android:paddingStart="4dp"
-            android:drawablePadding="8dp"
-            android:ellipsize="end"
-            android:gravity="center_vertical"
-            android:singleLine="true"
-            android:textAlignment="viewStart"
-            android:textColor="@color/ntp_most_visited_text"
-            android:textSize="12sp" />
-
-        <org.chromium.chrome.browser.ntp.MostVisitedThumbnail
-            android:id="@+id/most_visited_thumbnail"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:contentDescription="@null" />
-    </LinearLayout>
-
-    <View
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:background="?attr/selectableItemBackground" />
-
-</org.chromium.chrome.browser.ntp.MostVisitedItemView>
diff --git a/chrome/android/java/res/layout/most_visited_layout.xml b/chrome/android/java/res/layout/most_visited_layout.xml
deleted file mode 100644
index 647245a..0000000
--- a/chrome/android/java/res/layout/most_visited_layout.xml
+++ /dev/null
@@ -1,10 +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. -->
-
-<org.chromium.chrome.browser.ntp.MostVisitedLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="0dp"
-    android:layout_height="0dp"
-    android:paddingTop="16dp" />
diff --git a/chrome/android/java/res/values-sw600dp/dimens.xml b/chrome/android/java/res/values-sw600dp/dimens.xml
index 19e81540..2fd051c 100644
--- a/chrome/android/java/res/values-sw600dp/dimens.xml
+++ b/chrome/android/java/res/values-sw600dp/dimens.xml
@@ -43,7 +43,6 @@
     <dimen name="widget_column_width">130dp</dimen>
 
     <!-- NTP dimensions -->
-    <dimen name="most_visited_spacing">16dp</dimen>
     <dimen name="ntp_logo_height">180dp</dimen>
     <dimen name="snippets_thumbnail_size">120dp</dimen>
 
diff --git a/chrome/android/java/res/values/colors.xml b/chrome/android/java/res/values/colors.xml
index 01b5b25..1d99359 100644
--- a/chrome/android/java/res/values/colors.xml
+++ b/chrome/android/java/res/values/colors.xml
@@ -88,8 +88,6 @@
     <!-- NTP Colors. Used on the bookmarks and recent tabs pages. -->
     <color name="ntp_bg">#fff</color>
     <color name="ntp_bg_incognito">#222</color>
-    <color name="ntp_most_visited_text">#333</color>
-    <color name="ntp_most_visited_bg">#f2f2f2</color>
     <color name="ntp_list_item_text">#333</color>
     <color name="ntp_list_header_text">#333</color>
     <color name="ntp_list_header_subtext">#969696</color>
diff --git a/chrome/android/java/res/values/dimens.xml b/chrome/android/java/res/values/dimens.xml
index 7b142f3d..da9a429f 100644
--- a/chrome/android/java/res/values/dimens.xml
+++ b/chrome/android/java/res/values/dimens.xml
@@ -247,19 +247,7 @@
     <dimen name="document_toolbar_menu_offset">5dp</dimen>
 
     <!-- NTP dimensions -->
-    <dimen name="most_visited_spacing">16dp</dimen>
-    <dimen name="most_visited_tile_width">156dp</dimen>
-    <dimen name="most_visited_thumbnail_width">148dp</dimen>
-    <dimen name="most_visited_thumbnail_height">94dp</dimen>
     <dimen name="most_visited_bg_corner_radius">2dp</dimen>
-    <!-- 250dp was chosen because it's smaller than the smallest dimension on the smallest device,
-         so we'll always have at least two columns of tiles (except in multiwindow with a narrow
-         window). -->
-    <dimen name="most_visited_two_column_min_width">250dp</dimen>
-    <!-- 450dp was chosen because it's greater than the width of the largest phone in portrait yet
-         less than the width of the smallest phone in landscape. So, we'll always have two columns
-         in portrait and three in landscape (except in atypical situations, like multiwindow). -->
-    <dimen name="most_visited_three_column_min_width">450dp</dimen>
     <dimen name="icon_most_visited_layout_max_width">504dp</dimen>
     <dimen name="icon_most_visited_layout_padding_top">16dp</dimen>
     <dimen name="icon_most_visited_layout_no_logo_padding_top">28dp</dimen>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
index 1e4f198..ebeaa20 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
@@ -130,6 +130,7 @@
 import org.chromium.content.common.ContentSwitches;
 import org.chromium.content_public.browser.ContentBitmapCallback;
 import org.chromium.content_public.browser.LoadUrlParams;
+import org.chromium.content_public.browser.WebContents;
 import org.chromium.content_public.browser.readback_types.ReadbackResponse;
 import org.chromium.policy.CombinedPolicyProvider.PolicyChangeListener;
 import org.chromium.printing.PrintManagerDelegateImpl;
@@ -1603,6 +1604,18 @@
         }
     }
 
+    /**
+     * @see Activity#onContextMenuClosed(Menu)
+     */
+    @Override
+    public void onContextMenuClosed(Menu menu) {
+        final Tab currentTab = getActivityTab();
+        if (currentTab == null) return;
+        WebContents webContents = currentTab.getWebContents();
+        if (webContents == null) return;
+        webContents.onContextMenuClosed();
+    }
+
     private void enableHardwareAcceleration() {
         // HW acceleration is disabled in the manifest. Enable it only on high-end devices.
         if (!SysUtils.isLowEndDevice()) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/FrozenNativePage.java b/chrome/android/java/src/org/chromium/chrome/browser/FrozenNativePage.java
index 98c4d2c..4f4cbc24 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/FrozenNativePage.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/FrozenNativePage.java
@@ -39,7 +39,6 @@
 
     @Override
     public View getView() {
-        assert false;
         return null;
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanel.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanel.java
index 1038d34..beb8190 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanel.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanel.java
@@ -158,6 +158,8 @@
 
     @Override
     public void closePanel(StateChangeReason reason, boolean animate) {
+        if (!isShowing()) return;
+
         super.closePanel(reason, animate);
 
         // If the close action is animated, the Layout will be hidden when
@@ -173,6 +175,8 @@
      * @param reason The reason the panel is being shown.
      */
     public void requestPanelShow(StateChangeReason reason) {
+        if (isShowing()) return;
+
         if (mPanelManager != null) {
             mPanelManager.requestPanelShow(this, reason);
         }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ContextMenuHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ContextMenuHelper.java
index 06be21a..e8e5785 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ContextMenuHelper.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ContextMenuHelper.java
@@ -17,6 +17,7 @@
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.chrome.browser.share.ShareHelper;
 import org.chromium.content.browser.ContentViewCore;
+import org.chromium.content_public.browser.WebContents;
 import org.chromium.ui.base.WindowAndroid;
 
 /**
@@ -60,21 +61,26 @@
      * @param params          The {@link ContextMenuParams} that indicate what menu items to show.
      */
     @CalledByNative
-    private void showContextMenu(ContentViewCore contentViewCore, ContextMenuParams params) {
+    private boolean showContextMenu(ContentViewCore contentViewCore, ContextMenuParams params) {
         final View view = contentViewCore.getContainerView();
 
         if (!shouldShowMenu(params)
                 || view == null
                 || view.getVisibility() != View.VISIBLE
                 || view.getParent() == null) {
-            return;
+            return false;
         }
 
         mCurrentContextMenuParams = params;
 
         view.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
         view.setOnCreateContextMenuListener(this);
-        view.showContextMenu();
+        if (view.showContextMenu()) {
+            WebContents webContents = contentViewCore.getWebContents();
+            if (webContents != null) webContents.onContextMenuOpened();
+            return true;
+        }
+        return false;
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java
index 93ae6526..53d60dd 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java
@@ -60,7 +60,6 @@
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Locale;
-import java.util.Set;
 
 import javax.annotation.Nullable;
 
@@ -125,8 +124,9 @@
     private boolean mIsShowingPromo;
     private boolean mDidLogPromoOutcome;
 
-    // Cached target languages for translation;
-    private List<String> mTargetLanguages;
+    // Cached native language data for translation;
+    private String mTranslateServiceTargetLanguage;
+    private String mAcceptLanguages;
 
     /**
      * Whether contextual search manager is currently promoting a tab. We should be ignoring hide
@@ -485,8 +485,8 @@
             mNetworkCommunicator.startSearchTermResolutionRequest(
                     mSelectionController.getSelectedText());
             didRequestSurroundings = true;
-            // Cache the target languages in case they are needed for translation.
-            if (!mPolicy.disableForceTranslationOnebox()) getReadableLanguages();
+            // Cache the native translate data, so JNI calls won't be made when time-critical.
+            cacheNativeTranslateData();
         } else {
             boolean shouldPrefetch = mPolicy.shouldPrefetchSearchResult(isTap);
             mSearchRequest = new ContextualSearchRequest(mSelectionController.getSelectedText(),
@@ -792,50 +792,50 @@
 
     /**
      * Gets the list of readable languages for the current user, with the first
-     * item in the list being the user's primary language.
+     * item in the list being the user's primary language (according to the Translate Service).
      * We assume that the user can read all languages that they can write.
      * @return The {@link List} of languages the user understands with their primary language first.
      */
     private List<String> getReadableLanguages() {
-        // May be cached.
-        if (mTargetLanguages != null) return mTargetLanguages;
-
         // Using LinkedHashSet keeps the entries both unique and ordered.
-        Set<String> uniqueLanguages = new LinkedHashSet<String>();
+        LinkedHashSet<String> uniqueLanguages = getProficientLanguages();
 
-        // The primary language always comes first.
-        uniqueLanguages.add(
-                trimLocaleToLanguage(nativeGetTargetLanguage(mNativeContextualSearchManagerPtr)));
-
-        // Next add languages the user knows how to write.
-        List<String> writable = getWritableLanguages();
-        for (int i = 0; i < writable.size(); i++) {
-            uniqueLanguages.add(trimLocaleToLanguage(writable.get(i)));
-        }
-
-        // Add the accept languages last, since they are a weaker hint than presence of a keyboard.
+        // Add the accept languages to the end, since they are a weaker hint than
+        // the proficient languages.
         List<String> acceptLanguages = getAcceptLanguages();
         for (int i = 0; i < acceptLanguages.size(); i++) {
             uniqueLanguages.add(trimLocaleToLanguage(acceptLanguages.get(i)));
         }
-        mTargetLanguages = new ArrayList<String>(uniqueLanguages);
-        return mTargetLanguages;
+        return new ArrayList<String>(uniqueLanguages);
     }
 
     /**
-     * Gets the list of writable languages for the current user, based on their IME keyboards.
-     * @return An ordered {@link List} of languages the user reads.
+     * Gets the list of languages that the current user is proficient using.
+     * The list produced is based on the Translation-Service's target language, supplemented
+     * with the user's IME keyboard locales.
+     * @return An ordered {@link List} of languages the user is proficient using.
      */
-    private List<String> getWritableLanguages() {
-        List<String> result = new ArrayList<String>();
+    private ArrayList<String> getProficientLanguageList() {
+        return new ArrayList<String>(getProficientLanguages());
+    }
+
+    /**
+     * Similar to {@link #getProficientLanguageList} except the the result is provided in
+     * a {@link LinkedHashSet} to provide access to a unique ordered list.
+     * @return a {@link LinkedHashSet} of languages the user is proficient using.
+     */
+    private LinkedHashSet<String> getProficientLanguages() {
+        LinkedHashSet<String> uniqueLanguages = new LinkedHashSet<String>();
+        // The primary language, according to the translation-service, always comes first.
+        uniqueLanguages.add(trimLocaleToLanguage(getNativeTranslateServiceTargetLanguage()));
+        // Merge in the IME locales, if possible.
         Context context = mActivity.getApplicationContext();
-        List<String> locales = context != null
-                ? new ArrayList<String>(UiUtils.getIMELocales(context))
-                : new ArrayList<String>();
-        for (int i = 0; i < locales.size(); i++) {
-            result.add(trimLocaleToLanguage(locales.get(i)));
+        if (context != null) {
+            for (String locale : UiUtils.getIMELocales(context)) {
+                uniqueLanguages.add(trimLocaleToLanguage(locale));
+            }
         }
-        return result;
+        return uniqueLanguages;
     }
 
     /**
@@ -843,7 +843,7 @@
      * @return The {@link List} of languages the user understands or does not want translated.
      */
     private List<String> getAcceptLanguages() {
-        String acceptLanguages = nativeGetAcceptLanguages(mNativeContextualSearchManagerPtr);
+        String acceptLanguages = getNativeAcceptLanguages();
         List<String> result = new ArrayList<String>();
         for (String language : acceptLanguages.split(",")) {
             result.add(language);
@@ -875,7 +875,7 @@
                 boolean doForceTranslate = !mPolicy.disableForceTranslationOnebox();
                 if (doForceTranslate && searchRequest != null) {
                     searchRequest.forceTranslation(sourceLanguage,
-                            mPolicy.bestTargetLanguage(getWritableLanguages()));
+                            mPolicy.bestTargetLanguage(getProficientLanguageList()));
                 }
                 // Log that conditions were right for translation, even though it may be disabled
                 // for an experiment so we can compare with the counter factual data.
@@ -897,13 +897,45 @@
             // The translation one-box won't actually show when the source text ends up being
             // the same as the target text, so we err on over-triggering.
             searchRequest.forceAutoDetectTranslation(
-                    mPolicy.bestTargetLanguage(getWritableLanguages()));
+                    mPolicy.bestTargetLanguage(getProficientLanguageList()));
         }
         // Log that conditions were right for translation, even though it may be disabled
         // for an experiment so we can compare with the counter factual data.
         ContextualSearchUma.logTranslateOnebox(shouldAutoDetectTranslate);
     }
 
+    /**
+     * Caches all the native translate language info, so we can avoid repeated JNI calls.
+     */
+    private void cacheNativeTranslateData() {
+        if (!mPolicy.disableForceTranslationOnebox()) {
+            getNativeTranslateServiceTargetLanguage();
+            getNativeAcceptLanguages();
+        }
+    }
+
+    /**
+     * @return The accept-languages string from the cache or from native code (when not cached).
+     */
+    private String getNativeAcceptLanguages() {
+        if (mAcceptLanguages == null) {
+            mAcceptLanguages = nativeGetAcceptLanguages(mNativeContextualSearchManagerPtr);
+        }
+        return mAcceptLanguages;
+    }
+
+    /**
+     * @return The Translate Service's target language string from the cache or from
+     *         native code (when not cached).
+     */
+    private String getNativeTranslateServiceTargetLanguage() {
+        if (mTranslateServiceTargetLanguage == null) {
+            mTranslateServiceTargetLanguage = nativeGetTargetLanguage(
+                    mNativeContextualSearchManagerPtr);
+        }
+        return mTranslateServiceTargetLanguage;
+    }
+
     // ============================================================================================
     // OverlayContentDelegate
     // ============================================================================================
@@ -1330,6 +1362,7 @@
     private native void nativeGatherSurroundingText(long nativeContextualSearchManager,
             String selection, boolean useResolvedSearchTerm, ContentViewCore baseContentViewCore,
             boolean maySendBasePageUrl);
+    // Don't call these directly, instead call the private methods that cache the results.
     private native String nativeGetTargetLanguage(long nativeContextualSearchManager);
     private native String nativeGetAcceptLanguages(long nativeContextualSearchManager);
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchPolicy.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchPolicy.java
index 3041cb31..54d19a2e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchPolicy.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchPolicy.java
@@ -447,7 +447,8 @@
     }
 
     /**
-     * Determines the best target language.
+     * @return The best target language from the ordered list, or the empty string if
+     *         none is available.
      */
     String bestTargetLanguage(List<String> targetLanguages) {
         // For now, we just return the first language, unless it's English
@@ -456,11 +457,13 @@
         // E.g. If this language doesn't match the user's server preferences, they might see a page
         // in one language and the one box translation in another, which might be confusing.
         // Also this logic should only apply on Android, where English setup is over used.
-        if (TextUtils.equals(targetLanguages.get(0), Locale.ENGLISH.getLanguage())
-                && targetLanguages.size() > 1) {
+        if (targetLanguages.size() > 1
+                && TextUtils.equals(targetLanguages.get(0), Locale.ENGLISH.getLanguage())) {
             return targetLanguages.get(1);
-        } else {
+        } else if (targetLanguages.size() > 0) {
             return targetLanguages.get(0);
+        } else {
+            return "";
         }
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkSigninActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkSigninActivity.java
index 93724dc9..2d0618d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkSigninActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkSigninActivity.java
@@ -15,7 +15,7 @@
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.signin.SigninManager;
 import org.chromium.chrome.browser.signin.SigninManager.SignInStateObserver;
-import org.chromium.chrome.browser.sync.SyncController;
+import org.chromium.chrome.browser.sync.ProfileSyncService;
 import org.chromium.sync.AndroidSyncSettings;
 import org.chromium.sync.AndroidSyncSettings.AndroidSyncSettingsObserver;
 import org.chromium.sync.signin.ChromeSigninController;
@@ -99,9 +99,9 @@
 
     @Override
     public void enableSync() {
-        final SyncController syncController = SyncController.get(this);
-        if (syncController != null) {
-            syncController.start();
+        ProfileSyncService syncService = ProfileSyncService.get();
+        if (syncService != null) {
+            syncService.requestStart();
         }
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/invalidation/InvalidationController.java b/chrome/android/java/src/org/chromium/chrome/browser/invalidation/InvalidationController.java
index 06887d1..13cf984 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/invalidation/InvalidationController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/invalidation/InvalidationController.java
@@ -237,6 +237,13 @@
     }
 
     /**
+     * Returns whether the invalidation client has been started.
+     */
+    public boolean isStarted() {
+        return mStarted;
+    }
+
+    /**
      * Called when a RecentTabsPage is opened.
      */
     public void onRecentTabsPageOpened() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/metrics/StartupMetrics.java b/chrome/android/java/src/org/chromium/chrome/browser/metrics/StartupMetrics.java
index 23ea0eaa..53dd01c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/metrics/StartupMetrics.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/metrics/StartupMetrics.java
@@ -4,9 +4,12 @@
 
 package org.chromium.chrome.browser.metrics;
 
+import android.content.Context;
 import android.content.Intent;
 import android.os.Handler;
+import android.preference.PreferenceManager;
 
+import org.chromium.base.ApplicationStatus;
 import org.chromium.base.metrics.RecordHistogram;
 
 /**
@@ -28,14 +31,26 @@
     private int mFirstActionTaken = NO_ACTIVITY;
 
     private boolean mIsMainIntent;
-    private long mSessionStartTimestamp;
     private Handler mHandler;
-    private boolean mRecordedHistogram;
+    // This ensures metrics are recorded only once per updateIntent(...) call.
+    private boolean mShouldRecordHistogram;
+
+    // Startup time is measured by two different time sources.
+    // {@code mStartTimeNanoMonotonic} is measured from a monotonic time source with nanosecond
+    // precision whereas {@code mStartTimeMilli} is measured from the wall clock with millisecond
+    // precision. The monotonic time source may not persist across reboots whereas the wall clock
+    // is subject to change by the user.
+    private long mStartTimeNanoMonotonic;
+    private long mStartTimeMilli;
 
     private static StartupMetrics sInstance;
 
     // Record only the first 10s.
     private static final long RECORDING_THRESHOLD_NS = 10000000000L;
+    private static final int MILLI_SEC_PER_MINUTE = 60000;
+    private static final int MINUTES_PER_30DAYS = 43200;
+    // Bucket sizes are exponential so we get minute level granularity for first 10 minutes.
+    private static final int NUM_BUCKETS = 50;
 
     public static StartupMetrics getInstance() {
         if (sInstance == null) {
@@ -46,7 +61,6 @@
 
     // Singleton
     private StartupMetrics() {
-        mSessionStartTimestamp = System.nanoTime();
         mHandler = new Handler();
     }
 
@@ -58,12 +72,13 @@
     public void updateIntent(Intent intent) {
         mIsMainIntent = intent != null && Intent.ACTION_MAIN.equals(intent.getAction());
         mFirstActionTaken = NO_ACTIVITY;
-        mSessionStartTimestamp = System.nanoTime();
-        mRecordedHistogram = false;
+        mStartTimeNanoMonotonic = System.nanoTime();
+        mStartTimeMilli = System.currentTimeMillis();
+        mShouldRecordHistogram = true;
     }
 
     private boolean isShortlyAfterChromeStarted() {
-        return (System.nanoTime() - mSessionStartTimestamp) <= RECORDING_THRESHOLD_NS;
+        return (System.nanoTime() - mStartTimeNanoMonotonic) <= RECORDING_THRESHOLD_NS;
     }
 
     private void setFirstAction(int type) {
@@ -103,12 +118,22 @@
 
     /** Records the startup data in a histogram. Should only be called after native is loaded. */
     public void recordHistogram(boolean onStop) {
-        if (mRecordedHistogram) return;
+        if (!mShouldRecordHistogram) return;
         if (!isShortlyAfterChromeStarted() || mFirstActionTaken != NO_ACTIVITY || onStop) {
             String histogramName = mIsMainIntent ? "MobileStartup.MainIntentAction" :
                     "MobileStartup.NonMainIntentAction";
             RecordHistogram.recordEnumeratedHistogram(histogramName, mFirstActionTaken, MAX_INDEX);
-            mRecordedHistogram = true;
+            mShouldRecordHistogram = false;
+            Context ctx = ApplicationStatus.getApplicationContext();
+            long lastUsedTimeMilli = PreferenceManager.getDefaultSharedPreferences(ctx).getLong(
+                    UmaSessionStats.LAST_USED_TIME_PREF, 0);
+            if (mIsMainIntent && (lastUsedTimeMilli > 0) && (mStartTimeMilli > lastUsedTimeMilli)
+                    && (mStartTimeMilli - lastUsedTimeMilli > Integer.MAX_VALUE)) {
+                // Measured in minutes and capped at a day with a bucket precision of 6 minutes.
+                RecordHistogram.recordCustomCountHistogram("MobileStartup.TimeSinceLastUse",
+                        (int) (mStartTimeMilli - lastUsedTimeMilli) / MILLI_SEC_PER_MINUTE, 1,
+                        MINUTES_PER_30DAYS, NUM_BUCKETS);
+            }
         } else {
             // Call back later to record the histogram after 10s have elapsed.
             mHandler.postDelayed(new Runnable() {
@@ -116,8 +141,7 @@
                 public void run() {
                     recordHistogram(false);
                 }
-            } , (RECORDING_THRESHOLD_NS - (System.nanoTime() - mSessionStartTimestamp)) / 1000000);
+            }, (RECORDING_THRESHOLD_NS - (System.nanoTime() - mStartTimeNanoMonotonic)) / 1000000);
         }
     }
-
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/metrics/UmaSessionStats.java b/chrome/android/java/src/org/chromium/chrome/browser/metrics/UmaSessionStats.java
index 941e38c..ccaea0d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/metrics/UmaSessionStats.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/metrics/UmaSessionStats.java
@@ -7,6 +7,7 @@
 import android.content.ComponentCallbacks;
 import android.content.Context;
 import android.content.res.Configuration;
+import android.preference.PreferenceManager;
 import android.text.TextUtils;
 
 import org.chromium.chrome.browser.preferences.PrefServiceBridge;
@@ -26,6 +27,8 @@
  * and the framework's MetricService.
  */
 public class UmaSessionStats implements NetworkChangeNotifier.ConnectionTypeObserver {
+    public static final String LAST_USED_TIME_PREF = "umasessionstats.lastusedtime";
+
     private static final String SAMSUNG_MULTWINDOW_PACKAGE = "com.sec.feature.multiwindow";
 
     private static long sNativeUmaSessionStats = 0;
@@ -141,6 +144,10 @@
 
         nativeUmaEndSession(sNativeUmaSessionStats);
         NetworkChangeNotifier.removeConnectionTypeObserver(this);
+        PreferenceManager.getDefaultSharedPreferences(mContext)
+                .edit()
+                .putLong(LAST_USED_TIME_PREF, System.currentTimeMillis())
+                .apply();
     }
 
     public static void logRendererCrash() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/MostVisitedItemView.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/MostVisitedItemView.java
deleted file mode 100644
index b2167f2..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/MostVisitedItemView.java
+++ /dev/null
@@ -1,85 +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.content.Context;
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.ColorDrawable;
-import android.graphics.drawable.Drawable;
-import android.util.AttributeSet;
-import android.widget.FrameLayout;
-import android.widget.TextView;
-
-import org.chromium.base.ApiCompatibilityUtils;
-import org.chromium.chrome.R;
-
-/**
- * Displays the title, thumbnail, and favicon of a most visited page. The item can be clicked, or
- * long-pressed to trigger a context menu with options to "open in new tab", "open in incognito
- * tab", or "remove".
- */
-public class MostVisitedItemView extends FrameLayout {
-
-    private static final int MISSING_FAVICON_COLOR = 0xffe6e6e8;
-
-    private TextView mTitleView;
-    private MostVisitedThumbnail mThumbnailView;
-    private int mFaviconSize;
-    private int mTitlePaddingStart;
-
-    /**
-     * Constructor for inflating from XML.
-     */
-    public MostVisitedItemView(Context context, AttributeSet attrs) {
-        super(context, attrs);
-    }
-
-    /**
-     * Initializes the item. This must be called immediately after construction.
-     *
-     * @param title The title of the page.
-     */
-    public void init(String title) {
-        mTitleView = (TextView) findViewById(R.id.most_visited_title);
-        mThumbnailView = (MostVisitedThumbnail) findViewById(R.id.most_visited_thumbnail);
-
-        mTitleView.setText(title);
-
-        // Add padding to fill the space where the favicon will be shown. Once the favicon is
-        // available (in setFavicon()), this extra padding will be removed and the favicon will be
-        // added as a compound drawable. This prevents the text from jumping around when the favicon
-        // becomes available.
-        mTitlePaddingStart = ApiCompatibilityUtils.getPaddingStart(mTitleView);
-        mFaviconSize = getResources().getDimensionPixelSize(R.dimen.default_favicon_size);
-        int extraPaddingStart = mFaviconSize + mTitleView.getCompoundDrawablePadding();
-        ApiCompatibilityUtils.setPaddingRelative(mTitleView, mTitlePaddingStart + extraPaddingStart,
-                0, 0, 0);
-    }
-
-    /**
-     * Update the thumbnail and trigger a redraw with the new thumbnail.
-     */
-    public void setThumbnail(Bitmap thumbnail) {
-        mThumbnailView.setThumbnail(thumbnail);
-    }
-
-    /**
-     * Update the favicon and trigger a redraw with the new favicon.
-     */
-    public void setFavicon(Bitmap favicon) {
-        Resources res = getResources();
-        Drawable d;
-        if (favicon != null) {
-            d = new BitmapDrawable(res, favicon);
-        } else {
-            d = new ColorDrawable(MISSING_FAVICON_COLOR);
-        }
-        d.setBounds(0, 0, mFaviconSize, mFaviconSize);
-        ApiCompatibilityUtils.setCompoundDrawablesRelative(mTitleView, d, null, null, null);
-        ApiCompatibilityUtils.setPaddingRelative(mTitleView, mTitlePaddingStart, 0, 0, 0);
-    }
-}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/MostVisitedLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/MostVisitedLayout.java
deleted file mode 100644
index bdf95cb9..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/MostVisitedLayout.java
+++ /dev/null
@@ -1,150 +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.content.Context;
-import android.content.res.Resources;
-import android.graphics.Canvas;
-import android.graphics.drawable.Drawable;
-import android.util.AttributeSet;
-import android.view.View;
-import android.widget.FrameLayout;
-
-import org.chromium.base.ApiCompatibilityUtils;
-import org.chromium.chrome.R;
-
-/**
- * A layout that arranges most visited items in a grid. All items must be the same size.
- */
-public class MostVisitedLayout extends FrameLayout {
-
-    private int mHorizontalSpacing;
-    private int mVerticalSpacing;
-    private int mTwoColumnMinWidth;
-    private int mThreeColumnMinWidth;
-
-    /**
-     * The ideal width of a child. The children may need be stretched or shrunk a bit to fill the
-     * available width.
-     */
-    private int mDefaultChildWidth;
-
-    private Drawable mEmptyTileDrawable;
-    private int mNumEmptyTiles;
-    private int mEmptyTileTop;
-    private int mFirstEmptyTileLeft;
-
-    /**
-     * @param context The view context in which this item will be shown.
-     * @param attrs The attributes of the XML tag that is inflating the view.
-     */
-    public MostVisitedLayout(Context context, AttributeSet attrs) {
-        super(context, attrs);
-        setWillNotDraw(false);
-
-        Resources res = getResources();
-        mHorizontalSpacing = res.getDimensionPixelOffset(R.dimen.most_visited_spacing);
-        mVerticalSpacing = mHorizontalSpacing;
-        mDefaultChildWidth = res.getDimensionPixelSize(R.dimen.most_visited_tile_width);
-        mTwoColumnMinWidth = res.getDimensionPixelOffset(R.dimen.most_visited_two_column_min_width);
-        mThreeColumnMinWidth = res.getDimensionPixelOffset(
-                R.dimen.most_visited_three_column_min_width);
-    }
-
-    @Override
-    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        // Determine the number of columns in the grid.
-        final int totalWidth = MeasureSpec.getSize(widthMeasureSpec);
-        int childWidth = mDefaultChildWidth;
-        int childWidthWithSpacing = childWidth + mHorizontalSpacing;
-
-        int numColumns;
-        if (totalWidth + mHorizontalSpacing >= 3 * childWidthWithSpacing) {
-            numColumns = 3;
-        } else if (totalWidth < mTwoColumnMinWidth) {
-            numColumns = 1;
-        } else {
-            numColumns = totalWidth < mThreeColumnMinWidth ? 2 : 3;
-
-            // Resize the tiles to make them fill the entire available width.
-            childWidthWithSpacing = Math.max(mHorizontalSpacing,
-                    (totalWidth + mHorizontalSpacing) / numColumns);
-            childWidth = childWidthWithSpacing - mHorizontalSpacing;
-        }
-
-        int childCount = getChildCount();
-        int childHeight = 0;
-        if (childCount > 0) {
-            // Measure the children.
-            int childWidthSpec = MeasureSpec.makeMeasureSpec(childWidth, MeasureSpec.EXACTLY);
-            int childHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
-            for (int i = 0; i < childCount; i++) {
-                getChildAt(i).measure(childWidthSpec, childHeightSpec);
-            }
-            childHeight = getChildAt(0).getMeasuredHeight();
-        }
-
-        // Arrange the children in a grid.
-        int childStart = 0;
-        int childTop = 0;
-        int column = 0;
-        boolean isRtl = ApiCompatibilityUtils.isLayoutRtl(this);
-        for (int i = 0; i < childCount; i++) {
-            View child = getChildAt(i);
-            MarginLayoutParams layoutParams = (MarginLayoutParams) child.getLayoutParams();
-            layoutParams.setMargins(isRtl ? 0 : childStart, childTop,
-                    isRtl ? childStart : 0, 0);
-            child.setLayoutParams(layoutParams);
-            column++;
-            if (column == numColumns) {
-                column = 0;
-                childStart = 0;
-                childTop += childHeight + mVerticalSpacing;
-            } else {
-                childStart += childWidthWithSpacing;
-            }
-        }
-
-        // Fill the rest of the current row with empty tiles.
-        if (column != 0) {
-            mNumEmptyTiles = numColumns - column;
-            mEmptyTileTop = childTop + getPaddingTop();
-            mFirstEmptyTileLeft = isRtl ? 0 : childStart;
-        } else {
-            mNumEmptyTiles = 0;
-        }
-
-        int numRows = (childCount + mNumEmptyTiles) / numColumns;
-        int totalHeight = getPaddingTop() + getPaddingBottom() + numRows * childHeight
-                + (numRows - 1) * mVerticalSpacing;
-
-        int gridWidth = numColumns * childWidthWithSpacing - mHorizontalSpacing;
-        setMeasuredDimension(gridWidth, resolveSize(totalHeight, heightMeasureSpec));
-    }
-
-    @Override
-    protected void onDraw(Canvas canvas) {
-        super.onDraw(canvas);
-        if (mNumEmptyTiles == 0 || getChildCount() == 0) return;
-
-        // Draw empty tiles.
-        if (mEmptyTileDrawable == null) {
-            mEmptyTileDrawable = ApiCompatibilityUtils.getDrawable(
-                    getResources(), R.drawable.most_visited_item_empty);
-        }
-        int tileLeft = mFirstEmptyTileLeft;
-        int tileWidth = getChildAt(0).getMeasuredWidth();
-        int tileHeight = getChildAt(0).getMeasuredHeight();
-        for (int i = 0; i < mNumEmptyTiles; i++) {
-            mEmptyTileDrawable.setBounds(
-                    tileLeft,
-                    mEmptyTileTop,
-                    tileLeft + tileWidth,
-                    mEmptyTileTop + tileHeight);
-            mEmptyTileDrawable.draw(canvas);
-            tileLeft += tileWidth + mHorizontalSpacing;
-        }
-    }
-}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/MostVisitedThumbnail.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/MostVisitedThumbnail.java
deleted file mode 100644
index 0d3edc6..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/MostVisitedThumbnail.java
+++ /dev/null
@@ -1,97 +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.content.Context;
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.Color;
-import android.graphics.Matrix;
-import android.util.AttributeSet;
-import android.widget.ImageView;
-
-import org.chromium.chrome.R;
-
-/**
- * Displays a thumbnail for a most visited item on the NTP.
- */
-public class MostVisitedThumbnail extends ImageView {
-
-    private final int mDesiredWidth;
-    private final int mDesiredHeight;
-    private Bitmap mThumbnail;
-    private Matrix mImageMatrix;
-
-    /**
-     * Constructor for inflating from XML.
-     */
-    public MostVisitedThumbnail(Context context, AttributeSet attrs) {
-        super(context, attrs);
-        Resources res = getResources();
-        mDesiredWidth = res.getDimensionPixelSize(R.dimen.most_visited_thumbnail_width);
-        mDesiredHeight = res.getDimensionPixelSize(R.dimen.most_visited_thumbnail_height);
-    }
-
-    /**
-     * Updates the thumbnail and trigger a redraw with the new thumbnail.
-     */
-    void setThumbnail(Bitmap thumbnail) {
-        mThumbnail = thumbnail;
-        if (thumbnail != null) {
-            setImageBitmap(thumbnail);
-            setScaleType(ImageView.ScaleType.MATRIX);
-            updateThumbnailMatrix();
-        } else {
-            setBackgroundColor(Color.WHITE);
-            setImageResource(R.drawable.most_visited_thumbnail_placeholder);
-            setScaleType(ImageView.ScaleType.CENTER);
-        }
-    }
-
-    /**
-     * Updates the matrix used to scale the thumbnail when drawing it. This needs to be called
-     * whenever the thumbnail changes or this view's size changes.
-     *
-     * This matrix ensures that the thumbnail is anchored at the top left corner of this view and
-     * is scaled as small as possible while still covering the entire view. Surprisingly, there's
-     * no way to get this behavior using the other ImageView.ScaleTypes.
-     */
-    private void updateThumbnailMatrix() {
-        if (mThumbnail == null) return;
-
-        if (mImageMatrix == null) mImageMatrix = new Matrix();
-        float widthScale = (float) getMeasuredWidth() / mThumbnail.getWidth();
-        float heightScale = (float) getMeasuredHeight() / mThumbnail.getHeight();
-        float scale = Math.max(widthScale, heightScale);
-        mImageMatrix.setScale(scale, scale);
-        setImageMatrix(mImageMatrix);
-    }
-
-    @Override
-    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
-        super.onSizeChanged(w, h, oldw, oldh);
-        updateThumbnailMatrix();
-    }
-
-    /**
-     * Maintains this view's aspect ratio, even when its width is constrained. We can't just use
-     * android:adjustViewBounds, since that won't work when the source drawable isn't set or when
-     * it's the "missing thumbnail" gray circle, which has a different aspect ratio than thumbnails.
-     */
-    @Override
-    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        int width = resolveSize(mDesiredWidth, widthMeasureSpec);
-        int height;
-        if (width == mDesiredWidth) {
-            height = mDesiredHeight;
-        } else {
-            // The width is fixed. Find the height that keeps the proper aspect ratio.
-            height = Math.round((float) mDesiredHeight / mDesiredWidth * width);
-            height = resolveSize(height, heightMeasureSpec);
-        }
-        super.onMeasure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
-                MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
-    }
-}
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 2c10a2fd..8539a53 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
@@ -96,7 +96,6 @@
     private LargeIconBridge mLargeIconBridge;
     private LogoBridge mLogoBridge;
     private boolean mSearchProviderHasLogo;
-    private boolean mIsIconMode;
     private final boolean mOptOutPromoShown;
     private String mOnLogoClickUrl;
     private String mAnimatedLogoUrl;
@@ -421,7 +420,7 @@
             for (int i = 0; i < items.length; i++) {
                 tileTypes[i] = items[i].getTileType();
             }
-            mMostVisitedSites.recordTileTypeMetrics(tileTypes, mIsIconMode);
+            mMostVisitedSites.recordTileTypeMetrics(tileTypes);
         }
     };
 
@@ -471,10 +470,8 @@
 
         LayoutInflater inflater = LayoutInflater.from(activity);
         mNewTabPageView = (NewTabPageView) inflater.inflate(R.layout.new_tab_page, null);
-        // TODO(newt): delete thumbnail mode once we're sure that icon mode has stuck for good.
-        mIsIconMode = true;
         mNewTabPageView.initialize(mNewTabPageManager, isInSingleUrlBarMode(activity),
-                mSearchProviderHasLogo, mIsIconMode);
+                mSearchProviderHasLogo);
 
         RecordHistogram.recordBooleanHistogram(
                 "NewTabPage.MobileIsUserOnline", NetworkChangeNotifier.isOnline());
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 d167031..d38d11b1 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
@@ -236,21 +236,18 @@
      *                with the page.
      * @param isSingleUrlBarMode Whether the NTP is in single URL bar mode.
      * @param searchProviderHasLogo Whether the search provider has a logo.
-     * @param isIconMode Whether to show the icon-based design, as opposed to the thumbnail design.
      */
     public void initialize(NewTabPageManager manager, boolean isSingleUrlBarMode,
-            boolean searchProviderHasLogo, boolean isIconMode) {
+            boolean searchProviderHasLogo) {
         mManager = manager;
 
         mScrollView = (NewTabScrollView) findViewById(R.id.ntp_scrollview);
         mScrollView.enableBottomShadow(SHADOW_COLOR);
         mContentView = (ViewGroup) findViewById(R.id.ntp_content);
 
-        mMostVisitedDesign = isIconMode
-                ? new IconMostVisitedDesign(getContext())
-                : new ThumbnailMostVisitedDesign(getContext());
+        mMostVisitedDesign = new MostVisitedDesign(getContext());
         ViewStub mostVisitedLayoutStub = (ViewStub) findViewById(R.id.most_visited_layout_stub);
-        mostVisitedLayoutStub.setLayoutResource(mMostVisitedDesign.getMostVisitedLayoutId());
+        mostVisitedLayoutStub.setLayoutResource(R.layout.icon_most_visited_layout);
         mMostVisitedLayout = (ViewGroup) mostVisitedLayoutStub.inflate();
         mMostVisitedDesign.initMostVisitedLayout(mMostVisitedLayout, searchProviderHasLogo);
 
@@ -783,7 +780,7 @@
             if (item == null) {
                 String displayTitle = getTitleForDisplay(title, url);
                 item = new MostVisitedItem(mManager, title, url, i);
-                View view = mMostVisitedDesign.createMostVisitedItemView(inflater, url, title,
+                View view = mMostVisitedDesign.createMostVisitedItemView(inflater, url,
                         displayTitle, item, isInitialLoad);
                 item.initView(view);
             }
@@ -810,8 +807,7 @@
             String[] urls, String[] faviconUrls, String[] largeIconUrls) {
         for (int i = 0; i < urls.length; i++) {
             final String url = urls[i];
-            boolean useLargeIcon =
-                    mMostVisitedDesign.preferLargeIcons() && !largeIconUrls[i].isEmpty();
+            boolean useLargeIcon = !largeIconUrls[i].isEmpty();
             // Only fetch one of favicon or large icon based on what is required on the NTP.
             // The other will be fetched on visiting the site.
             String iconUrl = useLargeIcon ? largeIconUrls[i] : faviconUrls[i];
@@ -858,144 +854,9 @@
     }
 
     /**
-     * Interface for creating the most visited layout and tiles.
-     * TODO(newt): delete this once a single design has been chosen.
-     */
-    private interface MostVisitedDesign {
-        int getNumberOfTiles(boolean searchProviderHasLogo);
-        int getMostVisitedLayoutId();
-        int getMostVisitedLayoutBleed();
-        void initMostVisitedLayout(ViewGroup mostVisitedLayout, boolean searchProviderHasLogo);
-        void setSearchProviderHasLogo(View mostVisitedLayout, boolean hasLogo);
-        View createMostVisitedItemView(LayoutInflater inflater, String url, String title,
-                String displayTitle, MostVisitedItem item, boolean isInitialLoad);
-        void onIconUpdated(String url);
-        boolean preferLargeIcons();
-    }
-
-    /**
-     * The old most visited design, where each tile shows a thumbnail of the page, a small favicon,
-     * and the title.
-     */
-    private class ThumbnailMostVisitedDesign implements MostVisitedDesign {
-
-        private static final int NUM_TILES = 6;
-        private static final int FAVICON_CORNER_RADIUS_DP = 2;
-        private static final int FAVICON_TEXT_SIZE_DP = 10;
-        private static final int FAVICON_BACKGROUND_COLOR = 0xff969696;
-
-        private int mDesiredFaviconSize;
-        private RoundedIconGenerator mFaviconGenerator;
-
-        ThumbnailMostVisitedDesign(Context context) {
-            Resources res = context.getResources();
-            mDesiredFaviconSize = res.getDimensionPixelSize(R.dimen.default_favicon_size);
-            int desiredFaviconSizeDp = Math.round(
-                    mDesiredFaviconSize / res.getDisplayMetrics().density);
-            mFaviconGenerator = new RoundedIconGenerator(
-                    context, desiredFaviconSizeDp, desiredFaviconSizeDp, FAVICON_CORNER_RADIUS_DP,
-                    FAVICON_BACKGROUND_COLOR, FAVICON_TEXT_SIZE_DP);
-        }
-
-        @Override
-        public int getNumberOfTiles(boolean searchProviderHasLogo) {
-            return NUM_TILES;
-        }
-
-        @Override
-        public int getMostVisitedLayoutId() {
-            return R.layout.most_visited_layout;
-        }
-
-        @Override
-        public int getMostVisitedLayoutBleed() {
-            return 0;
-        }
-
-        @Override
-        public void initMostVisitedLayout(ViewGroup mostVisitedLayout,
-                boolean searchProviderHasLogo) {
-        }
-
-        @Override
-        public void setSearchProviderHasLogo(View mostVisitedLayout, boolean hasLogo) {}
-
-        @Override
-        public View createMostVisitedItemView(LayoutInflater inflater, final String url,
-                String title, String displayTitle, final MostVisitedItem item,
-                final boolean isInitialLoad) {
-            final MostVisitedItemView view = (MostVisitedItemView) inflater.inflate(
-                    R.layout.most_visited_item, mMostVisitedLayout, false);
-            view.init(displayTitle);
-
-            ThumbnailCallback thumbnailCallback = new ThumbnailCallback() {
-                @Override
-                public void onMostVisitedURLsThumbnailAvailable(Bitmap thumbnail,
-                        boolean isLocalThumbnail) {
-                    view.setThumbnail(thumbnail);
-                    if (thumbnail == null) {
-                        item.setTileType(MostVisitedTileType.THUMBNAIL_DEFAULT);
-                    } else if (isLocalThumbnail) {
-                        item.setTileType(MostVisitedTileType.THUMBNAIL_LOCAL);
-                    } else {
-                        item.setTileType(MostVisitedTileType.THUMBNAIL_SERVER);
-                    }
-                    mSnapshotMostVisitedChanged = true;
-                    if (isInitialLoad) loadTaskCompleted();
-                }
-            };
-            if (isInitialLoad) mPendingLoadTasks++;
-            mManager.getURLThumbnail(url, thumbnailCallback);
-
-            FaviconImageCallback faviconCallback = new FaviconImageCallback() {
-                @Override
-                public void onFaviconAvailable(Bitmap image, String iconUrl) {
-                    if (image == null) {
-                        image = mFaviconGenerator.generateIconForUrl(url);
-                    }
-                    view.setFavicon(image);
-                    mSnapshotMostVisitedChanged = true;
-                    if (isInitialLoad) loadTaskCompleted();
-                }
-            };
-            if (isInitialLoad) mPendingLoadTasks++;
-            mManager.getLocalFaviconImageForURL(url, mDesiredFaviconSize, faviconCallback);
-
-            return view;
-        }
-
-        @Override
-        public void onIconUpdated(final String url) {
-            // Find a matching most visited item.
-            for (MostVisitedItem item : mMostVisitedItems) {
-                if (!item.getUrl().equals(url)) continue;
-
-                final MostVisitedItemView view = (MostVisitedItemView) item.getView();
-                FaviconImageCallback faviconCallback = new FaviconImageCallback() {
-                    @Override
-                    public void onFaviconAvailable(Bitmap image, String iconUrl) {
-                        if (image == null) {
-                            image = mFaviconGenerator.generateIconForUrl(url);
-                        }
-                        view.setFavicon(image);
-                        mSnapshotMostVisitedChanged = true;
-                    }
-                };
-                mManager.getLocalFaviconImageForURL(url, mDesiredFaviconSize, faviconCallback);
-                break;
-            }
-        }
-
-        @Override
-        public boolean preferLargeIcons() {
-            return false;
-        }
-    }
-
-    /**
      * The new-fangled design for most visited tiles, where each tile shows a large icon and title.
      */
-    private class IconMostVisitedDesign implements MostVisitedDesign {
+    private class MostVisitedDesign {
 
         private static final int NUM_TILES = 8;
         private static final int NUM_TILES_NO_LOGO = 12;
@@ -1012,7 +873,7 @@
         private int mDesiredIconSize;
         private RoundedIconGenerator mIconGenerator;
 
-        IconMostVisitedDesign(Context context) {
+        MostVisitedDesign(Context context) {
             Resources res = context.getResources();
             mMostVisitedLayoutBleed = res.getDimensionPixelSize(
                     R.dimen.icon_most_visited_layout_bleed);
@@ -1026,29 +887,20 @@
                     ICON_BACKGROUND_COLOR, ICON_TEXT_SIZE_DP);
         }
 
-        @Override
         public int getNumberOfTiles(boolean searchProviderHasLogo) {
             return searchProviderHasLogo ? NUM_TILES : NUM_TILES_NO_LOGO;
         }
 
-        @Override
-        public int getMostVisitedLayoutId() {
-            return R.layout.icon_most_visited_layout;
-        }
-
-        @Override
         public int getMostVisitedLayoutBleed() {
             return mMostVisitedLayoutBleed;
         }
 
-        @Override
         public void initMostVisitedLayout(ViewGroup mostVisitedLayout,
                 boolean searchProviderHasLogo) {
             ((IconMostVisitedLayout) mostVisitedLayout).setMaxRows(
                     searchProviderHasLogo ? MAX_ROWS : MAX_ROWS_NO_LOGO);
         }
 
-        @Override
         public void setSearchProviderHasLogo(View mostVisitedLayout, boolean hasLogo) {
             int paddingTop = getResources().getDimensionPixelSize(hasLogo
                     ? R.dimen.icon_most_visited_layout_padding_top
@@ -1091,9 +943,8 @@
             }
         }
 
-        @Override
         public View createMostVisitedItemView(LayoutInflater inflater, final String url,
-                String title, String displayTitle, MostVisitedItem item,
+                String displayTitle, MostVisitedItem item,
                 final boolean isInitialLoad) {
             final IconMostVisitedItemView view = (IconMostVisitedItemView) inflater.inflate(
                     R.layout.icon_most_visited_item, mMostVisitedLayout, false);
@@ -1106,7 +957,6 @@
             return view;
         }
 
-        @Override
         public void onIconUpdated(final String url) {
             // Find a matching most visited item.
             for (MostVisitedItem item : mMostVisitedItems) {
@@ -1117,10 +967,5 @@
                 }
             }
         }
-
-        @Override
-        public boolean preferLargeIcons() {
-            return true;
-        }
     }
 }
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 ff37261bd..445f69b 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
@@ -24,7 +24,7 @@
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.signin.SigninManager;
 import org.chromium.chrome.browser.signin.SigninManager.SignInStateObserver;
-import org.chromium.chrome.browser.sync.SyncController;
+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;
@@ -442,9 +442,9 @@
 
     @Override
     public void enableSync() {
-        SyncController syncController = SyncController.get(mContext);
-        if (syncController != null) {
-            syncController.start();
+        ProfileSyncService syncService = ProfileSyncService.get();
+        if (syncService != null) {
+            syncService.requestStart();
         }
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java
index 3d6fc680..f959c8a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java
@@ -205,7 +205,6 @@
     private boolean mSuggestionsShown;
     private boolean mUrlHasFocus;
     private boolean mUrlFocusedFromFakebox;
-    private boolean mHasRecordedUrlFocusSource;
 
     // Set to true when the user has started typing new input in the omnibox, set to false
     // when the omnibox loses focus or becomes empty.
@@ -276,7 +275,6 @@
             if (mIgnoreURLBarModification) return;
 
             if (!mHasStartedNewOmniboxEditSession && mNativeInitialized) {
-                RecordUserAction.record("MobileFirstEditInOmnibox");
                 mAutocomplete.resetSession();
                 mHasStartedNewOmniboxEditSession = true;
                 mNewOmniboxEditSessionTimestamp = SystemClock.elapsedRealtime();
@@ -951,12 +949,13 @@
     public void onUrlFocusChange(boolean hasFocus) {
         mUrlHasFocus = hasFocus;
         mUrlContainer.onUrlFocusChanged(hasFocus);
-        updateFocusSource(hasFocus);
         updateDeleteButtonVisibility();
         Tab currentTab = getCurrentTab();
         if (hasFocus) {
+            RecordUserAction.record("FocusLocation");
             mUrlBar.deEmphasizeUrl();
         } else {
+            mUrlFocusedFromFakebox = false;
             hideSuggestions();
 
             // Focus change caused by a close-tab may result in an invalid current tab.
@@ -2376,37 +2375,6 @@
         loadUrl(url, PageTransition.TYPED);
     }
 
-    /**
-     * Tracks how the URL bar was focused (i.e. from the omnibox or the fakebox) and records a UMA
-     * stat for this. Should be called whenever the URL bar gains or loses focus.
-     * @param hasFocus Whether the URL bar now has focus.
-     */
-    private void updateFocusSource(boolean hasFocus) {
-        if (!hasFocus) {
-            mUrlFocusedFromFakebox = false;
-            mHasRecordedUrlFocusSource = false;
-            return;
-        }
-
-        // Record UMA event for how the URL bar was focused.
-        if (mHasRecordedUrlFocusSource) return;
-
-        Tab currentTab = getCurrentTab();
-        if (currentTab == null) return;
-
-        String url = currentTab.getUrl();
-        if (mUrlFocusedFromFakebox) {
-            RecordUserAction.record("MobileFocusedFakeboxOnNtp");
-        } else {
-            if (currentTab.isNativePage() && NewTabPage.isNTPUrl(url)) {
-                RecordUserAction.record("MobileFocusedOmniboxOnNtp");
-            } else {
-                RecordUserAction.record("MobileFocusedOmniboxNotOnNtp");
-            }
-        }
-        mHasRecordedUrlFocusSource = true;
-    }
-
     @Override
     public void onTabLoadingNTP(NewTabPage ntp) {
         ntp.setFakeboxDelegate(this);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/PrivacyPreferences.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/PrivacyPreferences.java
index 021ece74..a4540e60e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/PrivacyPreferences.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/PrivacyPreferences.java
@@ -26,7 +26,6 @@
 import org.chromium.chrome.browser.preferences.PrefServiceBridge;
 import org.chromium.chrome.browser.preferences.Preferences;
 import org.chromium.chrome.browser.profiles.Profile;
-import org.chromium.chrome.browser.safebrowsing.SafeBrowsingFieldTrial;
 
 /**
  * Fragment to keep track of the all the privacy related preferences.
@@ -143,12 +142,6 @@
         safeBrowsingPref.setOnPreferenceChangeListener(this);
         safeBrowsingPref.setManagedPreferenceDelegate(mManagedPreferenceDelegate);
 
-        if (!SafeBrowsingFieldTrial.isEnabled()) {
-            preferenceScreen.removePreference(
-                    findPreference(PREF_SAFE_BROWSING_EXTENDED_REPORTING));
-            preferenceScreen.removePreference(findPreference(PREF_SAFE_BROWSING));
-        }
-
         ButtonPreference clearBrowsingData =
                 (ButtonPreference) findPreference(PREF_CLEAR_BROWSING_DATA);
         clearBrowsingData.setOnPreferenceClickListener(new OnPreferenceClickListener() {
@@ -234,16 +227,12 @@
 
         CheckBoxPreference extendedReportingPref =
                 (CheckBoxPreference) findPreference(PREF_SAFE_BROWSING_EXTENDED_REPORTING);
-        if (extendedReportingPref != null) {
-            extendedReportingPref.setChecked(
-                    prefServiceBridge.isSafeBrowsingExtendedReportingEnabled());
-        }
+        extendedReportingPref.setChecked(
+                prefServiceBridge.isSafeBrowsingExtendedReportingEnabled());
 
         CheckBoxPreference safeBrowsingPref =
                 (CheckBoxPreference) findPreference(PREF_SAFE_BROWSING);
-        if (safeBrowsingPref != null) {
-            safeBrowsingPref.setChecked(prefServiceBridge.isSafeBrowsingEnabled());
-        }
+        safeBrowsingPref.setChecked(prefServiceBridge.isSafeBrowsingEnabled());
 
         Preference doNotTrackPref = findPreference(PREF_DO_NOT_TRACK);
         if (prefServiceBridge.isDoNotTrackEnabled()) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/profiles/MostVisitedSites.java b/chrome/android/java/src/org/chromium/chrome/browser/profiles/MostVisitedSites.java
index c290dac6..176b3f6 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/profiles/MostVisitedSites.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/profiles/MostVisitedSites.java
@@ -139,11 +139,9 @@
      * Records metrics about which types of tiles are displayed.
      * @param tileTypes An array of values from MostVisitedTileType indicating the type of each
      *                  tile that's currently showing.
-     * @paral isIconMode Whether the icon-based version of the NTP is showing (as opposed to the
-     *                   thumbnail-based version).
      */
-    public void recordTileTypeMetrics(int[] tileTypes, boolean isIconMode) {
-        nativeRecordTileTypeMetrics(mNativeMostVisitedSites, tileTypes, isIconMode);
+    public void recordTileTypeMetrics(int[] tileTypes) {
+        nativeRecordTileTypeMetrics(mNativeMostVisitedSites, tileTypes);
     }
 
     /**
@@ -162,8 +160,7 @@
     private native void nativeGetURLThumbnail(long nativeMostVisitedSites, String url,
             ThumbnailCallback callback);
     private native void nativeBlacklistUrl(long nativeMostVisitedSites, String url);
-    private native void nativeRecordTileTypeMetrics(long nativeMostVisitedSites, int[] tileTypes,
-            boolean isIconMode);
+    private native void nativeRecordTileTypeMetrics(long nativeMostVisitedSites, int[] tileTypes);
     private native void nativeRecordOpenedMostVisitedItem(long nativeMostVisitedSites, int index,
             int tileType);
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/safebrowsing/SafeBrowsingFieldTrial.java b/chrome/android/java/src/org/chromium/chrome/browser/safebrowsing/SafeBrowsingFieldTrial.java
deleted file mode 100644
index 5935f72..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/safebrowsing/SafeBrowsingFieldTrial.java
+++ /dev/null
@@ -1,28 +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.safebrowsing;
-
-import android.text.TextUtils;
-
-import org.chromium.components.variations.VariationsAssociatedData;
-
-/**
- *  Field Trial support for Safe Browsing on Chrome for Android.
- */
-public final class SafeBrowsingFieldTrial {
-    private static final String FIELD_TRIAL_NAME = "SafeBrowsingAndroid";
-    private static final String ENABLED_PARAM = "enabled";
-    private static final String ENABLED_VALUE = "true";
-
-    /*
-     * @return whether the SafeBrowsingAndroid field trial is marked as "enabled"
-     */
-    public static boolean isEnabled() {
-        return TextUtils.equals(ENABLED_VALUE,
-                VariationsAssociatedData.getVariationParamValue(FIELD_TRIAL_NAME, ENABLED_PARAM));
-    }
-
-    private SafeBrowsingFieldTrial() {}
-}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninHelper.java
index f8f658e2..e3fbd3438 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninHelper.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninHelper.java
@@ -22,7 +22,6 @@
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.signin.SigninManager.SignInFlowObserver;
 import org.chromium.chrome.browser.sync.ProfileSyncService;
-import org.chromium.chrome.browser.sync.SyncController;
 import org.chromium.sync.AndroidSyncSettings;
 import org.chromium.sync.signin.AccountManagerHelper;
 import org.chromium.sync.signin.ChromeSigninController;
@@ -113,7 +112,6 @@
 
     private final OAuth2TokenService mOAuth2TokenService;
 
-    @Nullable private final SyncController mSyncController;
 
     public static SigninHelper get(Context context) {
         synchronized (LOCK) {
@@ -130,7 +128,6 @@
         mSigninManager = SigninManager.get(mContext);
         mAccountTrackerService = AccountTrackerService.get(mContext);
         mOAuth2TokenService = OAuth2TokenService.getForProfile(Profile.getLastUsedProfile());
-        mSyncController = SyncController.get(context);
         mChromeSigninController = ChromeSigninController.get(mContext);
     }
 
@@ -266,13 +263,10 @@
             public void onSigninComplete() {
                 if (mProfileSyncService != null) {
                     mProfileSyncService.setSetupInProgress(false);
-                }
-
-                if (mSyncController != null) {
                     if (isSyncWanted) {
-                        mSyncController.start();
+                        mProfileSyncService.requestStart();
                     } else {
-                        mSyncController.stop();
+                        mProfileSyncService.requestStop();
                     }
                 }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninManager.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninManager.java
index 5fa4567..97026a51 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninManager.java
@@ -25,7 +25,6 @@
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.notifications.GoogleServicesNotificationController;
 import org.chromium.chrome.browser.sync.ProfileSyncService;
-import org.chromium.chrome.browser.sync.SyncController;
 import org.chromium.sync.AndroidSyncSettings;
 import org.chromium.sync.signin.ChromeSigninController;
 
@@ -503,7 +502,7 @@
                 if (profileSyncService != null) {
                     profileSyncService.setSetupInProgress(
                             signInSync == SIGNIN_SYNC_SETUP_IN_PROGRESS);
-                    SyncController.get(mContext).start();
+                    profileSyncService.requestStart();
                 }
 
                 if (observer != null) observer.onSigninComplete();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sync/SyncController.java b/chrome/android/java/src/org/chromium/chrome/browser/sync/SyncController.java
index d3a8c6a..e988f75 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/sync/SyncController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/sync/SyncController.java
@@ -4,7 +4,6 @@
 
 package org.chromium.chrome.browser.sync;
 
-import android.accounts.Account;
 import android.app.Activity;
 import android.content.Context;
 
@@ -19,13 +18,10 @@
 import org.chromium.chrome.browser.identity.UniqueIdentificationGeneratorFactory;
 import org.chromium.chrome.browser.invalidation.InvalidationController;
 import org.chromium.chrome.browser.signin.AccountManagementFragment;
-import org.chromium.chrome.browser.signin.SigninManager;
-import org.chromium.chrome.browser.signin.SigninManager.SignInFlowObserver;
 import org.chromium.chrome.browser.sync.ui.PassphraseActivity;
 import org.chromium.sync.AndroidSyncSettings;
 import org.chromium.sync.ModelType;
 import org.chromium.sync.PassphraseType;
-import org.chromium.sync.signin.AccountManagerHelper;
 import org.chromium.sync.signin.ChromeSigninController;
 
 import javax.annotation.Nullable;
@@ -121,79 +117,15 @@
     }
 
     /**
-     * Trigger Chromium sign in of the given account.
-     *
-     * This also ensure that sync setup is not in progress anymore, so sync will start after
-     * sync initialization has happened.
-     *
-     * @param activity the current activity.
-     * @param accountName the full account name.
-     */
-    @VisibleForTesting
-    public void signIn(Activity activity, String accountName) {
-        final Account account = AccountManagerHelper.createAccountFromName(accountName);
-
-        // The SigninManager handles most of the sign-in flow, and doFinishSignIn handles the
-        // ChromeShell specific details.
-        SigninManager signinManager = SigninManager.get(mContext);
-        signinManager.onFirstRunCheckDone();
-        final boolean passive = false;
-        signinManager.startSignIn(activity, account, passive, new SignInFlowObserver() {
-            @Override
-            public void onSigninComplete() {
-                SigninManager.get(mContext).logInSignedInUser();
-                mProfileSyncService.setSetupInProgress(false);
-                start();
-            }
-
-            @Override
-            public void onSigninCancelled() {
-                stop();
-            }
-        });
-    }
-
-    /**
      * Updates sync to reflect the state of the Android sync settings.
      */
-    public void updateSyncStateFromAndroid() {
-        if (AndroidSyncSettings.isSyncEnabled(mContext)) {
-            start();
-        } else {
-            stop();
-        }
-    }
-
-    /**
-     * Starts sync if the master sync flag is enabled.
-     *
-     * Affects native sync, the invalidation controller, and the Android sync settings.
-     */
-    public void start() {
-        ThreadUtils.assertOnUiThread();
-        if (AndroidSyncSettings.isMasterSyncEnabled(mContext)) {
-            Log.d(TAG, "Enabling sync");
-            InvalidationController.get(mContext).ensureStartedAndUpdateRegisteredTypes();
+    private void updateSyncStateFromAndroid() {
+        boolean isSyncEnabled = AndroidSyncSettings.isSyncEnabled(mContext);
+        if (isSyncEnabled == mProfileSyncService.isSyncRequested()) return;
+        if (isSyncEnabled) {
             mProfileSyncService.requestStart();
-            AndroidSyncSettings.enableChromeSync(mContext);
-        }
-    }
-
-    /**
-     * Stops Sync if a user is currently signed in.
-     *
-     * Affects native sync, the invalidation controller, and the Android sync settings.
-     */
-    public void stop() {
-        ThreadUtils.assertOnUiThread();
-        Log.d(TAG, "Disabling sync");
-        InvalidationController.get(mContext).stop();
-        mProfileSyncService.requestStop();
-        if (AndroidSyncSettings.isMasterSyncEnabled(mContext)) {
-            // Only disable Android's Chrome sync setting if we weren't disabled
-            // by the master sync setting. This way, when master sync is enabled
-            // they will both be on and sync will start again.
-            AndroidSyncSettings.disableChromeSync(mContext);
+        } else {
+            mProfileSyncService.requestStop();
         }
     }
 
@@ -206,12 +138,24 @@
     @Override
     public void syncStateChanged() {
         ThreadUtils.assertOnUiThread();
-        // Make the Java state match the native state.
+        InvalidationController invalidationController = InvalidationController.get(mContext);
         if (mProfileSyncService.isSyncRequested()) {
-            AndroidSyncSettings.enableChromeSync(mContext);
+            if (!invalidationController.isStarted()) {
+                invalidationController.ensureStartedAndUpdateRegisteredTypes();
+            }
+            if (!AndroidSyncSettings.isSyncEnabled(mContext)) {
+                assert AndroidSyncSettings.isMasterSyncEnabled(mContext);
+                AndroidSyncSettings.enableChromeSync(mContext);
+            }
         } else {
-            if (AndroidSyncSettings.isMasterSyncEnabled(mContext)) {
-                // See comment in stop().
+            if (invalidationController.isStarted()) {
+                invalidationController.stop();
+            }
+            if (AndroidSyncSettings.isSyncEnabled(mContext)) {
+                // Both Android's master and Chrome sync setting are enabled, so we want to disable
+                // the Chrome sync setting to match isSyncRequested. We have to be careful not to
+                // disable it when isSyncRequested becomes false due to master sync being disabled
+                // so that sync will turn back on if master sync is re-enabled.
                 AndroidSyncSettings.disableChromeSync(mContext);
             }
         }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sync/ui/SyncCustomizationFragment.java b/chrome/android/java/src/org/chromium/chrome/browser/sync/ui/SyncCustomizationFragment.java
index 7b29116..a175a3a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/sync/ui/SyncCustomizationFragment.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/sync/ui/SyncCustomizationFragment.java
@@ -31,7 +31,6 @@
 import org.chromium.chrome.browser.invalidation.InvalidationController;
 import org.chromium.chrome.browser.preferences.ChromeSwitchPreference;
 import org.chromium.chrome.browser.sync.ProfileSyncService;
-import org.chromium.chrome.browser.sync.SyncController;
 import org.chromium.sync.AndroidSyncSettings;
 import org.chromium.sync.ModelType;
 import org.chromium.sync.PassphraseType;
@@ -151,11 +150,10 @@
             @Override
             public boolean onPreferenceChange(Preference preference, Object newValue) {
                 assert canDisableSync();
-                SyncController syncController = SyncController.get(getActivity());
                 if ((boolean) newValue) {
-                    syncController.start();
+                    mProfileSyncService.requestStart();
                 } else {
-                    syncController.stop();
+                    mProfileSyncService.requestStop();
                 }
                 // Must be done asynchronously because the switch state isn't updated
                 // until after this function exits.
@@ -562,7 +560,7 @@
                 || !canDisableSync()) {
             return false;
         }
-        SyncController.get(getActivity()).stop();
+        mProfileSyncService.requestStop();
         mSyncSwitchPreference.setChecked(false);
         // setChecked doesn't trigger the callback, so update manually.
         updateSyncStateFromSwitch();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java
index 8066da2..84c53ae 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java
@@ -2015,8 +2015,8 @@
 
     private void destroyNativePage() {
         if (mNativePage == null) return;
+        if (mTabView != null) mTabView.removeView(mNativePage.getView());
 
-        mTabView.removeView(mNativePage.getView());
         mNativePage.destroy();
         mNativePage = null;
     }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/BindingManagerInDocumentModeIntegrationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/BindingManagerInDocumentModeIntegrationTest.java
index 742ae00..beb0bc84 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/BindingManagerInDocumentModeIntegrationTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/BindingManagerInDocumentModeIntegrationTest.java
@@ -43,12 +43,12 @@
 
         void assertIsInForeground(final int pid) {
             try {
-                assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
+                CriteriaHelper.pollForCriteria(new Criteria() {
                     @Override
                     public boolean isSatisfied() {
                         return mProcessInForegroundMap.get(pid);
                     }
-                }));
+                });
             } catch (InterruptedException ie) {
                 fail();
             }
@@ -56,12 +56,12 @@
 
         void assertIsInBackground(final int pid) {
             try {
-                assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
+                CriteriaHelper.pollForCriteria(new Criteria() {
                     @Override
                     public boolean isSatisfied() {
                         return !mProcessInForegroundMap.get(pid);
                     }
-                }));
+                });
             } catch (InterruptedException ie) {
                 fail();
             }
@@ -69,12 +69,12 @@
 
         void assertSetInForegroundWasCalled(String message, final int pid) {
             try {
-                assertTrue(message, CriteriaHelper.pollForCriteria(new Criteria() {
+                CriteriaHelper.pollForCriteria(new Criteria(message) {
                     @Override
                     public boolean isSatisfied() {
                         return mProcessInForegroundMap.indexOfKey(pid) >= 0;
                     }
-                }));
+                });
             } catch (InterruptedException ie) {
                 fail();
             }
@@ -82,12 +82,12 @@
 
         void assertIsReleaseAllModerateBindingsCalled() {
             try {
-                assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
+                CriteriaHelper.pollForCriteria(new Criteria() {
                     @Override
                     public boolean isSatisfied() {
                         return mIsReleaseAllModerateBindingsCalled;
                     }
-                }));
+                });
             } catch (InterruptedException ie) {
                 fail();
             }
@@ -218,13 +218,13 @@
         assertTrue(ChildProcessLauncher.crashProcessForTesting(
                 tab.getContentViewCore().getCurrentRenderProcessId()));
 
-        assertTrue("Renderer crash wasn't noticed by the browser.",
-                CriteriaHelper.pollForCriteria(new Criteria() {
+        CriteriaHelper.pollForCriteria(
+                new Criteria("Renderer crash wasn't noticed by the browser.") {
                     @Override
                     public boolean isSatisfied() {
                         return tab.getContentViewCore().getCurrentRenderProcessId() == 0;
                     }
-                }));
+                });
 
         // Reload the tab, respawning the renderer.
         getInstrumentation().runOnMainSync(new Runnable() {
@@ -235,13 +235,13 @@
         });
 
         // Wait until the process is spawned and its visibility is determined.
-        assertTrue("Process for the crashed tab was not respawned.",
-                CriteriaHelper.pollForCriteria(new Criteria() {
+        CriteriaHelper.pollForCriteria(
+                new Criteria("Process for the crashed tab was not respawned.") {
                     @Override
                     public boolean isSatisfied() {
                         return tab.getContentViewCore().getCurrentRenderProcessId() != 0;
                     }
-                }));
+                });
 
         mBindingManager.assertSetInForegroundWasCalled(
                 "isInForeground() was not called for the process.",
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/BindingManagerIntegrationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/BindingManagerIntegrationTest.java
index 078f8d9..b4d54a7f 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/BindingManagerIntegrationTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/BindingManagerIntegrationTest.java
@@ -50,12 +50,12 @@
 
         void assertIsInForeground(final int pid) {
             try {
-                assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
+                CriteriaHelper.pollForCriteria(new Criteria() {
                     @Override
                     public boolean isSatisfied() {
                         return mProcessInForegroundMap.get(pid);
                     }
-                }));
+                });
             } catch (InterruptedException ie) {
                 fail();
             }
@@ -63,12 +63,12 @@
 
         void assertIsInBackground(final int pid) {
             try {
-                assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
+                CriteriaHelper.pollForCriteria(new Criteria() {
                     @Override
                     public boolean isSatisfied() {
                         return !mProcessInForegroundMap.get(pid);
                     }
-                }));
+                });
             } catch (InterruptedException ie) {
                 fail();
             }
@@ -76,12 +76,12 @@
 
         void assertSetInForegroundWasCalled(String message, final int pid) {
             try {
-                assertTrue(message, CriteriaHelper.pollForCriteria(new Criteria() {
+                CriteriaHelper.pollForCriteria(new Criteria(message) {
                     @Override
                     public boolean isSatisfied() {
                         return mProcessInForegroundMap.indexOfKey(pid) >= 0;
                     }
-                }));
+                });
             } catch (InterruptedException ie) {
                 fail();
             }
@@ -89,12 +89,12 @@
 
         void assertIsReleaseAllModerateBindingsCalled() {
             try {
-                assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
+                CriteriaHelper.pollForCriteria(new Criteria() {
                     @Override
                     public boolean isSatisfied() {
                         return mIsReleaseAllModerateBindingsCalled;
                     }
-                }));
+                });
             } catch (InterruptedException ie) {
                 fail();
             }
@@ -206,15 +206,14 @@
         // Wait for the new tab animations on phones to finish.
         if (!DeviceFormFactor.isTablet(getActivity())) {
             final ChromeActivity activity = getActivity();
-            assertTrue("Did not finish animation",
-                    CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
-                        @Override
-                        public boolean isSatisfied() {
-                            Layout layout = activity.getCompositorViewHolder()
-                                    .getLayoutManager().getActiveLayout();
-                            return !layout.isLayoutAnimating();
-                        }
-                    }));
+            CriteriaHelper.pollForUIThreadCriteria(new Criteria("Did not finish animation") {
+                @Override
+                public boolean isSatisfied() {
+                    Layout layout = activity.getCompositorViewHolder()
+                            .getLayoutManager().getActiveLayout();
+                    return !layout.isLayoutAnimating();
+                }
+            });
         }
         getInstrumentation().waitForIdleSync();
 
@@ -278,15 +277,14 @@
         // Wait for the new tab animations on phones to finish.
         if (!DeviceFormFactor.isTablet(getActivity())) {
             final ChromeActivity activity = getActivity();
-            assertTrue("Did not finish animation",
-                    CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
-                        @Override
-                        public boolean isSatisfied() {
-                            Layout layout = activity.getCompositorViewHolder()
-                                    .getLayoutManager().getActiveLayout();
-                            return !layout.isLayoutAnimating();
-                        }
-                    }));
+            CriteriaHelper.pollForUIThreadCriteria(new Criteria("Did not finish animation") {
+                @Override
+                public boolean isSatisfied() {
+                    Layout layout = activity.getCompositorViewHolder()
+                            .getLayoutManager().getActiveLayout();
+                    return !layout.isLayoutAnimating();
+                }
+            });
         }
         getInstrumentation().waitForIdleSync();
 
@@ -311,13 +309,13 @@
         assertTrue(ChildProcessLauncher.crashProcessForTesting(
                 tabs[1].getContentViewCore().getCurrentRenderProcessId()));
 
-        assertTrue("Renderer crash wasn't noticed by the browser.",
-                CriteriaHelper.pollForCriteria(new Criteria() {
+        CriteriaHelper.pollForCriteria(
+                new Criteria("Renderer crash wasn't noticed by the browser.") {
                     @Override
                     public boolean isSatisfied() {
                         return tabs[1].getContentViewCore().getCurrentRenderProcessId() == 0;
                     }
-                }));
+                });
 
         // Switch to the tab that crashed in background.
         getInstrumentation().runOnMainSync(new Runnable() {
@@ -328,13 +326,13 @@
         });
 
         // Wait until the process is spawned and its visibility is determined.
-        assertTrue("Process for the crashed tab was not respawned.",
-                CriteriaHelper.pollForCriteria(new Criteria() {
+        CriteriaHelper.pollForCriteria(
+                new Criteria("Process for the crashed tab was not respawned.") {
                     @Override
                     public boolean isSatisfied() {
                         return tabs[1].getContentViewCore().getCurrentRenderProcessId() != 0;
                     }
-                }));
+                });
 
         mBindingManager.assertSetInForegroundWasCalled(
                 "isInForeground() was not called for the process.",
@@ -377,13 +375,13 @@
         assertTrue(ChildProcessLauncher.crashProcessForTesting(
                 tab.getContentViewCore().getCurrentRenderProcessId()));
 
-        assertTrue("Renderer crash wasn't noticed by the browser.",
-                CriteriaHelper.pollForCriteria(new Criteria() {
+        CriteriaHelper.pollForCriteria(
+                new Criteria("Renderer crash wasn't noticed by the browser.") {
                     @Override
                     public boolean isSatisfied() {
                         return tab.getContentViewCore().getCurrentRenderProcessId() == 0;
                     }
-                }));
+                });
 
         // Reload the tab, respawning the renderer.
         getInstrumentation().runOnMainSync(new Runnable() {
@@ -394,13 +392,13 @@
         });
 
         // Wait until the process is spawned and its visibility is determined.
-        assertTrue("Process for the crashed tab was not respawned.",
-                CriteriaHelper.pollForCriteria(new Criteria() {
+        CriteriaHelper.pollForCriteria(
+                new Criteria("Process for the crashed tab was not respawned.") {
                     @Override
                     public boolean isSatisfied() {
                         return tab.getContentViewCore().getCurrentRenderProcessId() != 0;
                     }
-                }));
+                });
 
         mBindingManager.assertSetInForegroundWasCalled(
                 "isInForeground() was not called for the process.",
@@ -536,7 +534,7 @@
         tabs[0] = getActivity().getActivityTab();
         singleClickView(tabs[0].getView());
 
-        assertTrue("Child tab isn't opened.", CriteriaHelper.pollForCriteria(new Criteria() {
+        CriteriaHelper.pollForCriteria(new Criteria("Child tab isn't opened.") {
             @Override
             public boolean isSatisfied() {
                 return getActivity().getCurrentTabModel().getCount() == 2
@@ -547,7 +545,7 @@
                                    .getCurrentRenderProcessId()
                         != 0;
             }
-        }));
+        });
         tabs[1] = getActivity().getActivityTab();
         assertEquals(tabs[0].getContentViewCore().getCurrentRenderProcessId(),
                 tabs[1].getContentViewCore().getCurrentRenderProcessId());
@@ -564,13 +562,13 @@
         assertTrue(ChildProcessLauncher.crashProcessForTesting(
                 tabs[1].getContentViewCore().getCurrentRenderProcessId()));
 
-        assertTrue("Renderer crash wasn't noticed by the browser.",
-                CriteriaHelper.pollForCriteria(new Criteria() {
+        CriteriaHelper.pollForCriteria(
+                new Criteria("Renderer crash wasn't noticed by the browser.") {
                     @Override
                     public boolean isSatisfied() {
                         return tabs[1].getContentViewCore().getCurrentRenderProcessId() == 0;
                     }
-                }));
+                });
         // Reload the tab, respawning the renderer.
         getInstrumentation().runOnMainSync(new Runnable() {
             @Override
@@ -580,13 +578,13 @@
         });
 
         // Wait until the process is spawned and its visibility is determined.
-        assertTrue("Process for the crashed tab was not respawned.",
-                CriteriaHelper.pollForCriteria(new Criteria() {
+        CriteriaHelper.pollForCriteria(
+                new Criteria("Process for the crashed tab was not respawned.") {
                     @Override
                     public boolean isSatisfied() {
                         return tabs[1].getContentViewCore().getCurrentRenderProcessId() != 0;
                     }
-                }));
+                });
 
         mBindingManager.assertSetInForegroundWasCalled(
                 "setInForeground() was not called for the process.",
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/ChromeTabbedActivityLollipopAndAboveTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/ChromeTabbedActivityLollipopAndAboveTest.java
index 87d6146..a7b6ddc 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/ChromeTabbedActivityLollipopAndAboveTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/ChromeTabbedActivityLollipopAndAboveTest.java
@@ -40,13 +40,13 @@
         // Make sure that ChromeTabbedActivity started up.
         Context context = getInstrumentation().getTargetContext();
         assertFalse(FeatureUtilities.isDocumentMode(context));
-        assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 Activity lastActivity = ApplicationStatus.getLastTrackedFocusedActivity();
                 return lastActivity instanceof ChromeTabbedActivity;
             }
-        }));
+        });
 
         // Try launching a DocumentActivity.
         Runnable runnable = new Runnable() {
@@ -66,7 +66,7 @@
                 getInstrumentation(), DocumentActivity.class, runnable);
 
         // ApplicationStatus should note that the DocumentActivity isn't running anymore.
-        assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 List<WeakReference<Activity>> activities = ApplicationStatus.getRunningActivities();
@@ -75,7 +75,7 @@
                 }
                 return true;
             }
-        }));
+        });
     }
 
     @Override
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/ContentViewFocusTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/ContentViewFocusTest.java
index 6abcc3f..ee23283 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/ContentViewFocusTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/ContentViewFocusTest.java
@@ -106,14 +106,14 @@
             }
         });
 
-        assertTrue("Layout still requesting Tab Android view be attached",
-                CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(
+                new Criteria("Layout still requesting Tab Android view be attached") {
                     @Override
                     public boolean isSatisfied() {
                         LayoutManager driver = getActivity().getLayoutManager();
                         return !driver.getActiveLayout().shouldDisplayContentOverlay();
                     }
-                }));
+                });
 
         // Make sure the view loses focus. It is immediately given focus back
         // because it's the only focusable view.
@@ -127,14 +127,14 @@
             }
         });
 
-        assertTrue("Layout not requesting Tab Android view be attached",
-                CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(
+                new Criteria("Layout not requesting Tab Android view be attached") {
                     @Override
                     public boolean isSatisfied() {
                         LayoutManager driver = getActivity().getLayoutManager();
                         return driver.getActiveLayout().shouldDisplayContentOverlay();
                     }
-                }));
+                });
 
         assertTrue("Content view didn't regain focus", blockForFocusChanged());
         assertFalse("Unexpected focus change", haveFocusChanges());
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/HistoryUITest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/HistoryUITest.java
index 748cb1e1..c24aa9a 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/HistoryUITest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/HistoryUITest.java
@@ -143,7 +143,7 @@
      */
     private void assertResultCountReaches(final ContentViewCore cvc, final int expected)
             throws InterruptedException {
-        assertTrue(CriteriaHelper.pollForCriteria(
+        CriteriaHelper.pollForCriteria(
                 new Criteria() {
                     @Override
                     public boolean isSatisfied() {
@@ -157,7 +157,7 @@
                             return false;
                         }
                     }
-                }));
+                });
     }
 
     /*
@@ -280,13 +280,12 @@
         assertNotNull("Could not find Clear button.", clearButton);
 
         TestTouchUtils.performClickOnMainSync(getInstrumentation(), clearButton);
-        assertTrue("Clear browsing dialog never hidden",
-                CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
-                    @Override
-                    public boolean isSatisfied() {
-                        return !clearBrowsingFragment.isVisible();
-                    }
-                }));
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria("Clear browsing dialog never hidden") {
+            @Override
+            public boolean isSatisfied() {
+                return !clearBrowsingFragment.isVisible();
+            }
+        });
 
         final ChromeActivity mainActivity = ActivityUtils.waitForActivity(
                 getInstrumentation(), getActivity().getClass(), new Runnable() {
@@ -301,14 +300,13 @@
                     }
                 });
         assertNotNull("Main never resumed", mainActivity);
-        assertTrue("Main tab never restored", CriteriaHelper.pollForUIThreadCriteria(
-                new Criteria() {
-                    @Override
-                    public boolean isSatisfied() {
-                        return mainActivity.getActivityTab() != null
-                                && !mainActivity.getActivityTab().isFrozen();
-                    }
-                }));
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria("Main tab never restored") {
+            @Override
+            public boolean isSatisfied() {
+                return mainActivity.getActivityTab() != null
+                        && !mainActivity.getActivityTab().isFrozen();
+            }
+        });
         JavaScriptUtils.executeJavaScriptAndWaitForResult(
                 mainActivity.getCurrentContentViewCore().getWebContents(), "reloadHistory()");
         assertResultCountReaches(getActivity().getCurrentContentViewCore(), 0);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/ItemChooserDialogTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/ItemChooserDialogTest.java
index 8559fda..f7e15e55 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/ItemChooserDialogTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/ItemChooserDialogTest.java
@@ -77,8 +77,8 @@
         return dialog;
     }
 
-    private void selectItem(Dialog dialog, int position, final String expectedItemId)
-            throws InterruptedException {
+    private void selectItem(Dialog dialog, int position, final String expectedItemId,
+            final boolean expectedEnabledState) throws InterruptedException {
         final ListView items = (ListView) dialog.findViewById(R.id.items);
         final Button button = (Button) dialog.findViewById(R.id.positive);
 
@@ -96,10 +96,12 @@
         CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
-                return button.isEnabled();
+                return button.isEnabled() == expectedEnabledState;
             }
         });
 
+        if (!expectedEnabledState) return;
+
         // TODO(finnur): Stop using coordinates 10, 10 when crbug.com/532237 is fixed.
         TouchCommon.singleClickView(button, 10, 10);
 
@@ -151,7 +153,7 @@
         assertFalse(button.isEnabled());
 
         // Select the first item and verify it got selected.
-        selectItem(dialog, 1, "key");
+        selectItem(dialog, 1, "key", true);
 
         mChooserDialog.dismiss();
     }
@@ -169,9 +171,9 @@
 
         // Disable one item and try to select it.
         mChooserDialog.setEnabled("key", false);
-        selectItem(dialog, 1, "None");
+        selectItem(dialog, 1, "None", false);
         // The other is still selectable.
-        selectItem(dialog, 2, "key2");
+        selectItem(dialog, 2, "key2", true);
 
         mChooserDialog.dismiss();
     }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/ModalDialogTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/ModalDialogTest.java
index 0ffc5d8..c080911 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/ModalDialogTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/ModalDialogTest.java
@@ -282,10 +282,8 @@
         });
 
         // Closing the tab should have dismissed the dialog.
-        boolean criteriaSatisfied = CriteriaHelper.pollForCriteria(
-                new JavascriptAppModalDialogShownCriteria(false));
-        assertTrue("The dialog should have been dismissed when its tab was closed.",
-                criteriaSatisfied);
+        CriteriaHelper.pollForCriteria(new JavascriptAppModalDialogShownCriteria(
+                "The dialog should have been dismissed when its tab was closed.", false));
     }
 
     /**
@@ -307,9 +305,8 @@
         helper.evaluateJavaScriptForTests(
                 getActivity().getCurrentContentViewCore().getWebContents(),
                 script);
-        boolean criteriaSatisfied = CriteriaHelper.pollForCriteria(
-                new JavascriptAppModalDialogShownCriteria(true));
-        assertTrue("Could not spawn or locate a modal dialog.", criteriaSatisfied);
+        CriteriaHelper.pollForCriteria(new JavascriptAppModalDialogShownCriteria(
+                "Could not spawn or locate a modal dialog.", true));
         return helper;
     }
 
@@ -344,10 +341,11 @@
         });
     }
 
-    private static class JavascriptAppModalDialogShownCriteria implements Criteria {
+    private static class JavascriptAppModalDialogShownCriteria extends Criteria {
         private final boolean mShouldBeShown;
 
-        public JavascriptAppModalDialogShownCriteria(boolean shouldBeShown) {
+        public JavascriptAppModalDialogShownCriteria(String error, boolean shouldBeShown) {
+            super(error);
             mShouldBeShown = shouldBeShown;
         }
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/NavigateTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/NavigateTest.java
index 672c12f..be7e7fa 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/NavigateTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/NavigateTest.java
@@ -59,7 +59,7 @@
             throws InterruptedException {
         new TabLoadObserver(getActivity().getActivityTab(), startUrl).assertLoaded();
 
-        assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 final UrlBar urlBar = (UrlBar) getActivity().findViewById(R.id.url_bar);
@@ -68,7 +68,7 @@
                 return TextUtils.equals(expectedLocation(endUrl), urlBar.getText().toString())
                         && TextUtils.equals(endUrl, getActivity().getActivityTab().getUrl());
             }
-        }));
+        });
     }
 
     /**
@@ -91,8 +91,7 @@
         });
         final LocationBarLayout locationBar =
                 (LocationBarLayout) getActivity().findViewById(R.id.location_bar);
-        assertTrue("Omnibox Suggestions never shown.",
-                OmniboxTestUtils.waitForOmniboxSuggestions(locationBar));
+        OmniboxTestUtils.waitForOmniboxSuggestions(locationBar);
 
         Tab currentTab = getActivity().getActivityTab();
         final CallbackHelper loadedCallback = new CallbackHelper();
@@ -261,12 +260,12 @@
                 TestHttpServerClient.getUrl("chrome/test/data/android/redirect/one.html");
         typeInOmniboxAndNavigate(initialUrl);
 
-        assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
+        CriteriaHelper.pollForCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return getActivity().getActivityTab().getUrl().equals(redirectedUrl);
             }
-        }));
+        });
     }
 
     /**
@@ -291,12 +290,12 @@
         typeInOmniboxAndNavigate(initialUrl);
 
         // Now intent fallback should be triggered assuming 'non_existent' scheme cannot be handled.
-        assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
+        CriteriaHelper.pollForCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return getActivity().getActivityTab().getUrl().equals(targetUrl);
             }
-        }));
+        });
 
         // Check if Java redirections were removed from the history.
         // Note that if we try to go back in the test: NavigateToEntry() is called, but
@@ -416,13 +415,12 @@
             // Wait for the url to change.
             final Tab tab = TabModelUtils.getCurrentTab(model);
             assertWaitForPageScaleFactorMatch(0.75f);
-            assertTrue("Page url didn't change",
-                    CriteriaHelper.pollForCriteria(new Criteria() {
-                        @Override
-                        public boolean isSatisfied() {
-                            return mockedUrl.equals(getTabUrlOnUIThread(tab));
-                        }
-                    }, 5000, 50));
+            CriteriaHelper.pollForCriteria(new Criteria("Page url didn't change") {
+                @Override
+                public boolean isSatisfied() {
+                    return mockedUrl.equals(getTabUrlOnUIThread(tab));
+                }
+            }, 5000, 50);
 
             // Make sure that we're showing new content now.
             assertEquals("Still showing spoofed data", "\"Real\"", getTabBodyText(tab));
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/NavigationPopupTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/NavigationPopupTest.java
index 45419d1..df79606c 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/NavigationPopupTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/NavigationPopupTest.java
@@ -233,19 +233,18 @@
             }
         });
 
-        assertTrue("All favicons did not get updated.",
-                CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
-                    @Override
-                    public boolean isSatisfied() {
-                        NavigationHistory history = controller.mHistory;
-                        for (int i = 0; i < history.getEntryCount(); i++) {
-                            if (history.getEntryAtIndex(i).getFavicon() == null) {
-                                return false;
-                            }
-                        }
-                        return true;
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria("All favicons did not get updated.") {
+            @Override
+            public boolean isSatisfied() {
+                NavigationHistory history = controller.mHistory;
+                for (int i = 0; i < history.getEntryCount(); i++) {
+                    if (history.getEntryAtIndex(i).getFavicon() == null) {
+                        return false;
                     }
-                }));
+                }
+                return true;
+            }
+        });
 
         ThreadUtils.runOnUiThreadBlocking(new Runnable() {
             @Override
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/PopupTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/PopupTest.java
index 6fd25ef9..b91c3d0 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/PopupTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/PopupTest.java
@@ -60,12 +60,12 @@
     @Feature({"Popup"})
     public void testPopupInfobarAppears() throws Exception {
         loadUrl(POPUP_HTML_FILENAME);
-        assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return getNumInfobarsShowing() == 1;
             }
-        }));
+        });
     }
 
     @MediumTest
@@ -78,12 +78,12 @@
                 : getActivity().getTabModelSelector();
 
         loadUrl(POPUP_HTML_FILENAME);
-        assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return getNumInfobarsShowing() == 1;
             }
-        }));
+        });
         assertEquals(1, selector.getTotalTabCount());
         final InfoBarContainer container = selector.getCurrentTab().getInfoBarContainer();
         ArrayList<InfoBar> infobars = container.getInfoBars();
@@ -91,37 +91,37 @@
 
         // Wait until the animations are done, then click the "open popups" button.
         final InfoBar infobar = infobars.get(0);
-        assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return !container.isAnimating();
             }
-        }));
+        });
         TouchCommon.singleClickView(infobar.getView().findViewById(R.id.button_primary));
 
         // Document mode popups appear slowly and sequentially to prevent Android from throwing them
         // away, so use a long timeout.  http://crbug.com/498920.
-        assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 if (getNumInfobarsShowing() != 0) return false;
                 return TextUtils.equals("Popup #3", selector.getCurrentTab().getTitle());
             }
-        }, 7500, CriteriaHelper.DEFAULT_POLLING_INTERVAL));
+        }, 7500, CriteriaHelper.DEFAULT_POLLING_INTERVAL);
 
         assertEquals(4, selector.getTotalTabCount());
         int currentTabId = selector.getCurrentTab().getId();
 
         // Test that revisiting the original page makes popup windows immediately.
         loadUrl(POPUP_HTML_FILENAME);
-        assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 if (getNumInfobarsShowing() != 0) return false;
                 if (selector.getTotalTabCount() != 7) return false;
                 return TextUtils.equals("Popup #3", selector.getCurrentTab().getTitle());
             }
-        }, 7500, CriteriaHelper.DEFAULT_POLLING_INTERVAL));
+        }, 7500, CriteriaHelper.DEFAULT_POLLING_INTERVAL);
         assertNotSame(currentTabId, selector.getCurrentTab().getId());
     }
 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/PowerBroadcastReceiverTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/PowerBroadcastReceiverTest.java
index 88658d7d..6d26ffe 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/PowerBroadcastReceiverTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/PowerBroadcastReceiverTest.java
@@ -102,15 +102,13 @@
     /**
      * Waits to see if the runnable was run.
      */
-    public boolean runnableRan(final MockServiceRunnable runnable) throws Exception {
-        return CriteriaHelper.pollForCriteria(
-                new Criteria() {
-                    @Override
-                    public boolean isSatisfied() {
-                        return runnable.mRan;
-                    }
-                },
-                MS_TIMEOUT, MS_INTERVAL);
+    public void waitForRunnableRan(final MockServiceRunnable runnable) throws Exception {
+        CriteriaHelper.pollForCriteria(new Criteria() {
+            @Override
+            public boolean isSatisfied() {
+                return runnable.mRan;
+            }
+        }, MS_TIMEOUT, MS_INTERVAL);
     }
 
     /**
@@ -134,7 +132,7 @@
         pauseMain(true);
 
         // Check to see that the runnable gets run.
-        assertTrue("MockServiceRunnable didn't run after resuming Chrome.", runnableRan(runnable));
+        waitForRunnableRan(runnable);
         assertFalse("PowerBroadcastReceiver was still registered.", receiver.isRegistered());
     }
 
@@ -157,7 +155,13 @@
         pauseMain(false);
 
         // Wait enough time for the runnable to run(), if it's still in the handler.
-        assertFalse("MockServiceRunnable ran after resuming Chrome.", runnableRan(runnable));
+        try {
+            waitForRunnableRan(runnable);
+            fail("MockServiceRunnable ran after resuming Chrome.");
+        } catch (AssertionError e) {
+            // TODO(tedchoc): This is horrible.  This test should be rewritten.  It should not
+            //                require timing out a criteria to determine success.
+        }
         assertFalse("PowerBroadcastReceiver was still registered.", receiver.isRegistered());
     }
 
@@ -184,8 +188,13 @@
         pauseMain(true);
 
         // Wait enough time for the runnable to run(), if it's still in the handler.
-        boolean ranWhileScreenOff = runnableRan(runnable);
-        assertFalse("MockServiceRunnable ran even though screen was off.", ranWhileScreenOff);
+        try {
+            waitForRunnableRan(runnable);
+            fail("MockServiceRunnable ran after resuming Chrome.");
+        } catch (AssertionError e) {
+            // TODO(tedchoc): This is horrible.  This test should be rewritten.  It should not
+            //                require timing out a criteria to determine success.
+        }
         assertTrue("PowerBroadcastReceiver was not registered.", receiver.isRegistered());
 
         // Pretend to turn the screen on.
@@ -194,8 +203,7 @@
         receiver.onReceive(main, intent);
 
         // Wait enough time for the runnable to run(), if it's still in the handler.
-        boolean ranWhileScreenOn = runnableRan(runnable);
-        assertTrue("MockServiceRunnable didn't run when screen turned on.", ranWhileScreenOn);
+        waitForRunnableRan(runnable);
         assertFalse("PowerBroadcastReceiver wasn't unregistered.", receiver.isRegistered());
     }
 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/RepostFormWarningTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/RepostFormWarningTest.java
index d385b6a..559ddf9 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/RepostFormWarningTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/RepostFormWarningTest.java
@@ -114,13 +114,13 @@
     }
 
     private AlertDialog waitForRepostFormWarningDialog() throws InterruptedException {
-        assertTrue("Form resubmission warning not shown", CriteriaHelper.pollForUIThreadCriteria(
-                new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(
+                new Criteria("Form resubmission warning not shown") {
                     @Override
                     public boolean isSatisfied() {
                         return RepostFormWarningDialog.getCurrentDialog() != null;
                     }
-                }));
+                });
         return ThreadUtils.runOnUiThreadBlockingNoException(new Callable<AlertDialog>() {
             @Override
             public AlertDialog call() throws Exception {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/SelectFileDialogTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/SelectFileDialogTest.java
index 62df886..bd6757f 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/SelectFileDialogTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/SelectFileDialogTest.java
@@ -60,7 +60,11 @@
         }
     }
 
-    private class IntentSentCriteria implements Criteria {
+    private class IntentSentCriteria extends Criteria {
+        public IntentSentCriteria() {
+            super("SelectFileDialog never sent an intent.");
+        }
+
         @Override
         public boolean isSatisfied() {
             return mActivityWindowAndroidForTest.lastIntent != null;
@@ -89,8 +93,7 @@
         mContentViewCore = getActivity().getCurrentContentViewCore();
         // TODO(aurimas) remove this wait once crbug.com/179511 is fixed.
         assertWaitForPageScaleFactorMatch(2);
-        assertTrue(
-                DOMUtils.waitForNonZeroNodeBounds(mContentViewCore.getWebContents(), "input_file"));
+        DOMUtils.waitForNonZeroNodeBounds(mContentViewCore.getWebContents(), "input_file");
     }
 
     /**
@@ -101,14 +104,12 @@
     @Feature({"TextInput", "Main"})
     public void testSelectFileAndCancelRequest() throws Throwable {
         DOMUtils.clickNode(this, mContentViewCore, "input_file");
-        assertTrue("SelectFileDialog never sent an intent.",
-                CriteriaHelper.pollForCriteria(new IntentSentCriteria()));
+        CriteriaHelper.pollForCriteria(new IntentSentCriteria());
         assertEquals(Intent.ACTION_CHOOSER, mActivityWindowAndroidForTest.lastIntent.getAction());
         resetActivityWindowAndroidForTest();
 
         DOMUtils.clickNode(this, mContentViewCore, "input_file_multiple");
-        assertTrue("SelectFileDialog never sent an intent.",
-                CriteriaHelper.pollForCriteria(new IntentSentCriteria()));
+        CriteriaHelper.pollForCriteria(new IntentSentCriteria());
         assertEquals(Intent.ACTION_CHOOSER, mActivityWindowAndroidForTest.lastIntent.getAction());
         Intent contentIntent = (Intent)
                 mActivityWindowAndroidForTest.lastIntent.getParcelableExtra(Intent.EXTRA_INTENT);
@@ -119,15 +120,13 @@
         resetActivityWindowAndroidForTest();
 
         DOMUtils.clickNode(this, mContentViewCore, "input_image");
-        assertTrue("SelectFileDialog never sent an intent.",
-                CriteriaHelper.pollForCriteria(new IntentSentCriteria()));
+        CriteriaHelper.pollForCriteria(new IntentSentCriteria());
         assertEquals(MediaStore.ACTION_IMAGE_CAPTURE,
                 mActivityWindowAndroidForTest.lastIntent.getAction());
         resetActivityWindowAndroidForTest();
 
         DOMUtils.clickNode(this, mContentViewCore, "input_audio");
-        assertTrue("SelectFileDialog never sent an intent.",
-                CriteriaHelper.pollForCriteria(new IntentSentCriteria()));
+        CriteriaHelper.pollForCriteria(new IntentSentCriteria());
         assertEquals(MediaStore.Audio.Media.RECORD_SOUND_ACTION,
                 mActivityWindowAndroidForTest.lastIntent.getAction());
         resetActivityWindowAndroidForTest();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/TabTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/TabTest.java
index a3ea6d1..5d4e037 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/TabTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/TabTest.java
@@ -97,24 +97,24 @@
             }
         });
 
-        assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return mTab.isHidden();
             }
-        }));
+        });
         assertTrue(mTab.needsReload());
         assertFalse(mTab.isShowingSadTab());
 
         ApplicationTestUtils.launchChrome(getInstrumentation().getTargetContext());
 
         // The tab should be restored and visible.
-        assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return !mTab.isHidden();
             }
-        }));
+        });
         assertFalse(mTab.needsReload());
         assertFalse(mTab.isShowingSadTab());
     }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/TabsOpenedFromExternalAppTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/TabsOpenedFromExternalAppTest.java
index 2ec9546..e4ca854 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/TabsOpenedFromExternalAppTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/TabsOpenedFromExternalAppTest.java
@@ -48,11 +48,12 @@
     private static final String EXTERNAL_APP_1_ID = "app1";
     private static final String EXTERNAL_APP_2_ID = "app2";
 
-    static class ElementFocusedCriteria implements Criteria {
+    static class ElementFocusedCriteria extends Criteria {
         private final Tab mTab;
         private final String mElementId;
 
         public ElementFocusedCriteria(Tab tab, String elementId) {
+            super("Text-field in page not focused.");
             mTab = tab;
             // Add quotes to match returned value from JS.
             mElementId = "\"" + elementId + "\"";
@@ -89,12 +90,13 @@
         }
     }
 
-    static class ElementTextIsCriteria implements Criteria {
+    static class ElementTextIsCriteria extends Criteria {
         private final Tab mTab;
         private final String mElementId;
         private final String mExpectedText;
 
         public ElementTextIsCriteria(Tab tab, String elementId, String expectedText) {
+            super("Page does not have the text typed in.");
             mTab = tab;
             mElementId = elementId;
             mExpectedText = expectedText;
@@ -145,13 +147,12 @@
             }
         });
         if (createNewTab) {
-            assertTrue("Failed to select different tab",
-                    CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
-                        @Override
-                        public boolean isSatisfied() {
-                            return getActivity().getActivityTab() != originalTab;
-                        }
-                    }));
+            CriteriaHelper.pollForUIThreadCriteria(new Criteria("Failed to select different tab") {
+                @Override
+                public boolean isSatisfied() {
+                    return getActivity().getActivityTab() != originalTab;
+                }
+            });
         }
         ChromeTabUtils.waitForTabPageLoaded(getActivity().getActivityTab(), url);
     }
@@ -428,17 +429,15 @@
         DOMUtils.clickNode(this, tab.getContentViewCore(), "textField");
 
         // Some processing needs to happen before the test-field has the focus.
-        assertTrue("Text-field in page not focused.", CriteriaHelper.pollForCriteria(
-                new ElementFocusedCriteria(
-                        getActivity().getActivityTab(), "textField"), 2000, 200));
+        CriteriaHelper.pollForCriteria(new ElementFocusedCriteria(
+                getActivity().getActivityTab(), "textField"), 2000, 200);
 
         // Now type something.
         getInstrumentation().sendStringSync("banana");
 
         // We also have to wait for the text to happen in the page.
-        assertTrue("Page does not have the text typed in.", CriteriaHelper.pollForCriteria(
-                new ElementTextIsCriteria(getActivity().getActivityTab(), "textField",
-                        "banana"), 2000, 200));
+        CriteriaHelper.pollForCriteria(new ElementTextIsCriteria(
+                getActivity().getActivityTab(), "textField", "banana"), 2000, 200);
 
         // Launch a second URL from the same app, it should open in a new tab.
         int originalTabCount = ChromeTabUtils.getNumOpenTabs(getActivity());
@@ -473,12 +472,12 @@
                 TabModelUtils.closeTabByIndex(getActivity().getCurrentTabModel(), 0);
             }
         });
-        assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return getActivity().getTabModelSelector().getTotalTabCount() == 0;
             }
-        }));
+        });
 
         // Open a tab via an external application.
         final Intent intent = new Intent(
@@ -489,12 +488,12 @@
         intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
         getInstrumentation().getTargetContext().startActivity(intent);
 
-        assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return getActivity().getTabModelSelector().getTotalTabCount() == 1;
             }
-        }));
+        });
         ApplicationTestUtils.assertWaitForPageScaleFactorMatch(getActivity(), 0.5f, false);
 
         // Long press the center of the page, which should bring up the context menu.
@@ -508,12 +507,12 @@
             }
         });
         TouchCommon.longPressView(view);
-        assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return observer.mContextMenu != null;
             }
-        }));
+        });
         getActivity().getActivityTab().removeObserver(observer);
 
         // Select the "open in new tab" option.
@@ -526,21 +525,21 @@
         });
 
         // The second tab should open in the background.
-        assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return getActivity().getTabModelSelector().getTotalTabCount() == 2;
             }
-        }));
+        });
 
         // Hitting "back" should close the tab, minimize Chrome, and select the background tab.
         // Confirm that the number of tabs is correct and that closing the tab didn't cause a crash.
         getActivity().onBackPressed();
-        assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return getActivity().getTabModelSelector().getTotalTabCount() == 1;
             }
-        }));
+        });
     }
 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/TabsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/TabsTest.java
index 9256c08..bdf2052f 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/TabsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/TabsTest.java
@@ -141,13 +141,12 @@
             }
         });
 
-        assertTrue("Tab never spawned in normal model.",
-                CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
-                    @Override
-                    public boolean isSatisfied() {
-                        return getActivity().getTabModelSelector().getModel(false).getCount() == 2;
-                    }
-                }));
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria("Tab never spawned in normal model.") {
+            @Override
+            public boolean isSatisfied() {
+                return getActivity().getTabModelSelector().getModel(false).getCount() == 2;
+            }
+        });
     }
 
     @MediumTest
@@ -239,7 +238,7 @@
             }
         });
 
-        assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 Tab tab = getActivity().getCurrentTabModel().getTabAt(1);
@@ -247,7 +246,7 @@
                 String expectedTitle = "new tab";
                 return title.startsWith(expectedTitle);
             }
-        }));
+        });
 
         ChromeTabUtils.closeCurrentTab(getInstrumentation(), getActivity());
         getInstrumentation().runOnMainSync(new Runnable() {
@@ -271,7 +270,7 @@
 
         // Make sure we're on the NTP
         Tab tab = getActivity().getActivityTab();
-        assertTrue("NTP never fully loaded.", NewTabPageTestUtils.waitForNtpLoaded(tab));
+        NewTabPageTestUtils.waitForNtpLoaded(tab);
 
         loadUrl(INITIAL_SIZE_TEST_URL);
 
@@ -914,14 +913,14 @@
                 }
             }
         });
-        assertTrue("Did not finish animation",
-                CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
-                    @Override
-                    public boolean isSatisfied() {
-                        Layout layout = getActivity().getLayoutManager().getActiveLayout();
-                        return !layout.isLayoutAnimating();
-                    }
-                }));
+
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria("Did not finish animation") {
+            @Override
+            public boolean isSatisfied() {
+                Layout layout = getActivity().getLayoutManager().getActiveLayout();
+                return !layout.isLayoutAnimating();
+            }
+        });
     }
 
     private void swipeToCloseNTabs(int number, boolean isLandscape, boolean isIncognito,
@@ -1203,12 +1202,12 @@
                 R.id.close_all_tabs_menu_id);
         UiUtils.settleDownUI(getInstrumentation());
 
-        assertTrue("Should be in overview mode", CriteriaHelper.pollForCriteria(new Criteria() {
+        CriteriaHelper.pollForCriteria(new Criteria("Should be in overview mode") {
             @Override
             public boolean isSatisfied() {
                 return getActivity().isInOverviewMode();
             }
-        }));
+        });
 
         int initialTabCount = getActivity().getCurrentTabModel().getCount();
         assertEquals("Tab count is expected to be 0 after closing all the tabs",
@@ -1397,8 +1396,8 @@
     }
 
     private void waitForStaticLayout() throws InterruptedException {
-        assertTrue("Static Layout never selected after side swipe",
-                CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(
+                new Criteria("Static Layout never selected after side swipe") {
                     @Override
                     public boolean isSatisfied() {
                         CompositorViewHolder compositorViewHolder = (CompositorViewHolder)
@@ -1407,7 +1406,7 @@
 
                         return layoutManager.getActiveLayout() instanceof StaticLayout;
                     }
-                }));
+                });
     }
 
     /**
@@ -1455,14 +1454,14 @@
             }
         });
 
-        assertTrue("Layout still requesting Tab Android view be attached",
-                CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(
+                new Criteria("Layout still requesting Tab Android view be attached") {
                     @Override
                     public boolean isSatisfied() {
                         LayoutManager driver = getActivity().getLayoutManager();
                         return !driver.getActiveLayout().shouldDisplayContentOverlay();
                     }
-                }));
+                });
 
         ThreadUtils.runOnUiThread(new Runnable() {
             @Override
@@ -1473,14 +1472,14 @@
             }
         });
 
-        assertTrue("Layout not requesting Tab Android view be attached",
-                CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(
+                new Criteria("Layout not requesting Tab Android view be attached") {
                     @Override
                     public boolean isSatisfied() {
                         LayoutManager driver = getActivity().getLayoutManager();
                         return driver.getActiveLayout().shouldDisplayContentOverlay();
                     }
-                }));
+                });
 
         assertFalse("Keyboard should not be shown",
                 org.chromium.ui.UiUtils.isKeyboardShowing(getActivity(), urlBar));
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/appmenu/AppMenuTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/appmenu/AppMenuTest.java
index e15d3c8..07a79878 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/appmenu/AppMenuTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/appmenu/AppMenuTest.java
@@ -92,12 +92,12 @@
                 mAppMenu.getPopup().getListView().setSelection(0);
             }
         });
-        assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
+        CriteriaHelper.pollForCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return getCurrentFocusedRow() == 0;
             }
-        }));
+        });
         getInstrumentation().waitForIdleSync();
     }
 
@@ -202,13 +202,12 @@
         getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
         showAppMenuAndAssertMenuShown();
         getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
-        assertTrue("AppMenu did not dismiss",
-                CriteriaHelper.pollForCriteria(new Criteria() {
-                    @Override
-                    public boolean isSatisfied() {
-                        return !mAppMenuHandler.isAppMenuShowing();
-                    }
-                }));
+        CriteriaHelper.pollForCriteria(new Criteria("AppMenu did not dismiss") {
+            @Override
+            public boolean isSatisfied() {
+                return !mAppMenuHandler.isAppMenuShowing();
+            }
+        });
     }
 
     private void showAppMenuAndAssertMenuShown() throws InterruptedException {
@@ -218,25 +217,23 @@
                 mAppMenuHandler.showAppMenu(null, false);
             }
         });
-        assertTrue("AppMenu did not show",
-                CriteriaHelper.pollForCriteria(new Criteria() {
-                    @Override
-                    public boolean isSatisfied() {
-                        return mAppMenuHandler.isAppMenuShowing();
-                    }
-                }));
+        CriteriaHelper.pollForCriteria(new Criteria("AppMenu did not show") {
+            @Override
+            public boolean isSatisfied() {
+                return mAppMenuHandler.isAppMenuShowing();
+            }
+        });
     }
 
     private void hitEnterAndAssertAppMenuDismissed() throws InterruptedException {
         getInstrumentation().waitForIdleSync();
         pressKey(KeyEvent.KEYCODE_ENTER);
-        assertTrue("AppMenu did not dismiss",
-                CriteriaHelper.pollForCriteria(new Criteria() {
-                    @Override
-                    public boolean isSatisfied() {
-                        return !mAppMenuHandler.isAppMenuShowing();
-                    }
-                }));
+        CriteriaHelper.pollForCriteria(new Criteria("AppMenu did not dismiss") {
+            @Override
+            public boolean isSatisfied() {
+                return !mAppMenuHandler.isAppMenuShowing();
+            }
+        });
     }
 
     private void moveToBoundary(boolean towardsTop, boolean movePast) throws InterruptedException {
@@ -246,25 +243,24 @@
         for (int index = getCurrentFocusedRow(); index != end; index += increment) {
             pressKey(towardsTop ? KeyEvent.KEYCODE_DPAD_UP : KeyEvent.KEYCODE_DPAD_DOWN);
             final int expectedPosition = index + increment;
-            assertTrue("Focus did not move to the next menu item",
-                    CriteriaHelper.pollForCriteria(new Criteria() {
+            CriteriaHelper.pollForCriteria(
+                    new Criteria("Focus did not move to the next menu item") {
                         @Override
                         public boolean isSatisfied() {
                             return getCurrentFocusedRow() == expectedPosition;
                         }
-                    }));
+                    });
         }
 
         // Try moving past it by one.
         if (movePast) {
             pressKey(towardsTop ? KeyEvent.KEYCODE_DPAD_UP : KeyEvent.KEYCODE_DPAD_DOWN);
-            assertTrue("Focus moved past the edge menu item",
-                    CriteriaHelper.pollForCriteria(new Criteria() {
-                        @Override
-                        public boolean isSatisfied() {
-                            return getCurrentFocusedRow() == end;
-                        }
-                    }));
+            CriteriaHelper.pollForCriteria(new Criteria("Focus moved past the edge menu item") {
+                @Override
+                public boolean isSatisfied() {
+                    return getCurrentFocusedRow() == end;
+                }
+            });
         }
 
         // The menu should stay open.
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillDialogControllerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillDialogControllerTest.java
index d196c99f..44d96d7 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillDialogControllerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillDialogControllerTest.java
@@ -713,22 +713,21 @@
     }
 
     private void waitForInputFieldFill(final WebContents webContents) throws InterruptedException {
-        assertTrue("requestAutocomplete() never completed.",
-                CriteriaHelper.pollForCriteria(new Criteria() {
-                    @Override
-                    public boolean isSatisfied() {
-                        String wasAutocompleted;
-                        try {
-                            wasAutocompleted = DOMUtils.getNodeContents(
-                                    webContents, "was-autocompleted");
-                        } catch (InterruptedException e) {
-                            return false;
-                        } catch (TimeoutException e) {
-                            return false;
-                        }
-                        return TextUtils.equals("succeeded", wasAutocompleted)
-                                || TextUtils.equals("failed", wasAutocompleted);
-                    }
-                }));
+        CriteriaHelper.pollForCriteria(new Criteria("requestAutocomplete() never completed.") {
+            @Override
+            public boolean isSatisfied() {
+                String wasAutocompleted;
+                try {
+                    wasAutocompleted = DOMUtils.getNodeContents(
+                            webContents, "was-autocompleted");
+                } catch (InterruptedException e) {
+                    return false;
+                } catch (TimeoutException e) {
+                    return false;
+                }
+                return TextUtils.equals("succeeded", wasAutocompleted)
+                        || TextUtils.equals("failed", wasAutocompleted);
+            }
+        });
     }
 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillKeyboardAccessoryTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillKeyboardAccessoryTest.java
index 54fee236..39bafc4 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillKeyboardAccessoryTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillKeyboardAccessoryTest.java
@@ -91,7 +91,7 @@
                         getActivity().getWindowAndroid().getKeyboardAccessoryView());
             }
         });
-        assertTrue(DOMUtils.waitForNonZeroNodeBounds(mWebContentsRef.get(), "fn"));
+        DOMUtils.waitForNonZeroNodeBounds(mWebContentsRef.get(), "fn");
     }
 
     /**
@@ -120,13 +120,12 @@
              InterruptedException, TimeoutException {
         loadTestPage(false);
         DOMUtils.clickNode(this, mViewCoreRef.get(), "fn");
-        assertTrue("Keyboard should be showing.",
-                CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
-                    @Override
-                    public boolean isSatisfied() {
-                        return UiUtils.isKeyboardShowing(getActivity(), mContainerRef.get());
-                    }
-                }));
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria("Keyboard should be showing.") {
+            @Override
+            public boolean isSatisfied() {
+                return UiUtils.isKeyboardShowing(getActivity(), mContainerRef.get());
+            }
+        });
         assertTrue("Keyboard accessory should be showing.",
                 ThreadUtils.runOnUiThreadBlocking(new Callable<Boolean>() {
                     @Override
@@ -145,21 +144,20 @@
              InterruptedException, TimeoutException {
         loadTestPage(false);
         DOMUtils.clickNode(this, mViewCoreRef.get(), "fn");
-        assertTrue("Keyboard should be showing.",
-                CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
-                    @Override
-                    public boolean isSatisfied() {
-                        return UiUtils.isKeyboardShowing(getActivity(), mContainerRef.get());
-                    }
-                }));
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria("Keyboard should be showing.") {
+            @Override
+            public boolean isSatisfied() {
+                return UiUtils.isKeyboardShowing(getActivity(), mContainerRef.get());
+            }
+        });
         ThreadUtils.runOnUiThreadBlocking(new Runnable() {
             @Override
             public void run() {
                 ((HorizontalScrollView) mKeyboardAccessoryRef.get()).scrollTo(2000, 0);
             }
         });
-        assertTrue("First suggestion should be off the screen after manual scroll.",
-                CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(
+                new Criteria("First suggestion should be off the screen after manual scroll.") {
                     @Override
                     public boolean isSatisfied() {
                         View suggestion = getSuggestionAt(0);
@@ -171,17 +169,17 @@
                             return false;
                         }
                     }
-                }));
+                });
         DOMUtils.clickNode(this, mViewCoreRef.get(), "ln");
-        assertTrue("First suggestion should be on the screen after switching fields.",
-                CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(
+                new Criteria("First suggestion should be on the screen after switching fields.") {
                     @Override
                     public boolean isSatisfied() {
                         int[] location = new int[2];
                         getSuggestionAt(0).getLocationOnScreen(location);
                         return location[0] > 0;
                     }
-                }));
+                });
     }
 
     /**
@@ -193,21 +191,20 @@
              InterruptedException, TimeoutException {
         loadTestPage(true);
         DOMUtils.clickNode(this, mViewCoreRef.get(), "fn");
-        assertTrue("Keyboard should be showing.",
-                CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
-                    @Override
-                    public boolean isSatisfied() {
-                        return UiUtils.isKeyboardShowing(getActivity(), mContainerRef.get());
-                    }
-                }));
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria("Keyboard should be showing.") {
+            @Override
+            public boolean isSatisfied() {
+                return UiUtils.isKeyboardShowing(getActivity(), mContainerRef.get());
+            }
+        });
         ThreadUtils.runOnUiThreadBlocking(new Runnable() {
             @Override
             public void run() {
                 ((HorizontalScrollView) mKeyboardAccessoryRef.get()).scrollTo(0, 0);
             }
         });
-        assertTrue("Last suggestion should be on the screen after manual scroll.",
-                CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(
+                new Criteria("Last suggestion should be on the screen after manual scroll.") {
                     @Override
                     public boolean isSatisfied() {
                         View suggestion = getSuggestionAt(2);
@@ -219,10 +216,10 @@
                             return false;
                         }
                     }
-                }));
+                });
         DOMUtils.clickNode(this, mViewCoreRef.get(), "ln");
-        assertTrue("Last suggestion should be off the screen after switching fields.",
-                CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(
+                new Criteria("Last suggestion should be off the screen after switching fields.") {
                     @Override
                     public boolean isSatisfied() {
                         View suggestion = getSuggestionAt(2);
@@ -234,7 +231,7 @@
                             return false;
                         }
                     }
-                }));
+                });
     }
 
     /**
@@ -247,13 +244,12 @@
              InterruptedException, TimeoutException {
         loadTestPage(false);
         DOMUtils.clickNode(this, mViewCoreRef.get(), "fn");
-        assertTrue("Keyboard should be showing.",
-                CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
-                    @Override
-                    public boolean isSatisfied() {
-                        return UiUtils.isKeyboardShowing(getActivity(), mContainerRef.get());
-                    }
-                }));
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria("Keyboard should be showing.") {
+            @Override
+            public boolean isSatisfied() {
+                return UiUtils.isKeyboardShowing(getActivity(), mContainerRef.get());
+            }
+        });
         ThreadUtils.runOnUiThreadBlocking(new Runnable() {
             @Override
             public void run() {
@@ -263,13 +259,12 @@
                 }
             }
         });
-        assertTrue("Keyboard should be hidden.",
-                CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
-                    @Override
-                    public boolean isSatisfied() {
-                        return !UiUtils.isKeyboardShowing(getActivity(), mContainerRef.get());
-                    }
-                }));
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria("Keyboard should be hidden.") {
+            @Override
+            public boolean isSatisfied() {
+                return !UiUtils.isKeyboardShowing(getActivity(), mContainerRef.get());
+            }
+        });
         assertTrue("Keyboard accessory should be hidden.",
                 ThreadUtils.runOnUiThreadBlocking(new Callable<Boolean>() {
                     @Override
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillPopupTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillPopupTest.java
index 8bc5a6d..e8c6be4 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillPopupTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillPopupTest.java
@@ -168,7 +168,7 @@
         assertEquals(1, mHelper.getNumberOfProfiles());
 
         // Click the input field for the first name.
-        assertTrue(DOMUtils.waitForNonZeroNodeBounds(webContents, "fn"));
+        DOMUtils.waitForNonZeroNodeBounds(webContents, "fn");
         DOMUtils.clickNode(this, viewCore, "fn");
 
         waitForKeyboardShowRequest(immw, 1);
@@ -303,52 +303,51 @@
 
     private void waitForKeyboardShowRequest(final TestInputMethodManagerWrapper immw,
             final int count) throws InterruptedException {
-        assertTrue("Keyboard was never requested to be shown.",
-                CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(
+                new Criteria("Keyboard was never requested to be shown.") {
                     @Override
                     public boolean isSatisfied() {
                         return immw.getShowSoftInputCounter() == count;
                     }
-                }));
+                });
     }
 
     private void waitForAnchorViewAdd(final ViewGroup view) throws InterruptedException {
-        assertTrue("Autofill Popup anchor view was never added.",
-                CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
-                    @Override
-                    public boolean isSatisfied() {
-                        return view.findViewById(R.id.dropdown_popup_window) != null;
-                    }
-                }));
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria(
+                "Autofill Popup anchor view was never added.") {
+            @Override
+            public boolean isSatisfied() {
+                return view.findViewById(R.id.dropdown_popup_window) != null;
+            }
+        });
     }
 
     private void waitForAutofillPopopShow(final AutofillPopup popup) throws InterruptedException {
-        assertTrue("Autofill Popup anchor view was never added.",
-                CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(
+                new Criteria("Autofill Popup anchor view was never added.") {
                     @Override
                     public boolean isSatisfied() {
                         // Wait until the popup is showing and onLayout() has happened.
                         return popup.isShowing() && popup.getListView() != null
                                 && popup.getListView().getHeight() != 0;
                     }
-                }));
+                });
     }
 
     private void waitForInputFieldFill(final WebContents webContents) throws InterruptedException {
-        assertTrue("First name field was never filled.",
-                CriteriaHelper.pollForCriteria(new Criteria() {
-                    @Override
-                    public boolean isSatisfied() {
-                        try {
-                            return TextUtils.equals(FIRST_NAME,
-                                    DOMUtils.getNodeValue(webContents, "fn"));
-                        } catch (InterruptedException e) {
-                            return false;
-                        } catch (TimeoutException e) {
-                            return false;
-                        }
-                    }
-                }));
+        CriteriaHelper.pollForCriteria(new Criteria("First name field was never filled.") {
+            @Override
+            public boolean isSatisfied() {
+                try {
+                    return TextUtils.equals(FIRST_NAME,
+                            DOMUtils.getNodeValue(webContents, "fn"));
+                } catch (InterruptedException e) {
+                    return false;
+                } catch (TimeoutException e) {
+                    return false;
+                }
+            }
+        });
     }
 
     private void assertLogged(String autofilledValue, String profileFullName) {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillPopupWithKeyboardTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillPopupWithKeyboardTest.java
index f514e76..6314a1f 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillPopupWithKeyboardTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillPopupWithKeyboardTest.java
@@ -82,7 +82,7 @@
                 viewRef.set(viewCoreRef.get().getContainerView());
             }
         });
-        assertTrue(DOMUtils.waitForNonZeroNodeBounds(webContentsRef.get(), "fn"));
+        DOMUtils.waitForNonZeroNodeBounds(webContentsRef.get(), "fn");
 
         // Click on the unfocused input element for the first time to focus on it. This brings up
         // the autofill popup and shows the keyboard at the same time. Showing the keyboard should
@@ -90,24 +90,23 @@
         DOMUtils.clickNode(this, viewCoreRef.get(), "fn");
 
         // Wait until the keyboard is showing.
-        assertTrue("Keyboard was never shown.",
-                CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
-                    @Override
-                    public boolean isSatisfied() {
-                        return UiUtils.isKeyboardShowing(
-                                getActivity(),
-                                getActivity().getCurrentContentViewCore().getContainerView());
-                    }
-                }));
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria("Keyboard was never shown.") {
+            @Override
+            public boolean isSatisfied() {
+                return UiUtils.isKeyboardShowing(
+                        getActivity(),
+                        getActivity().getCurrentContentViewCore().getContainerView());
+            }
+        });
 
         // Verify that the autofill popup is showing.
-        assertTrue("Autofill Popup anchor view was never added.",
-                CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(
+                new Criteria("Autofill Popup anchor view was never added.") {
                     @Override
                     public boolean isSatisfied() {
                         return viewRef.get().findViewById(R.id.dropdown_popup_window) != null;
                     }
-                }));
+                });
         Object popupObject = ThreadUtils.runOnUiThreadBlocking(new Callable<Object>() {
             @Override
             public Object call() {
@@ -116,12 +115,11 @@
         });
         assertTrue(popupObject instanceof AutofillPopup);
         final AutofillPopup popup = (AutofillPopup) popupObject;
-        assertTrue("Autofill Popup was never shown.",
-                CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
-                    @Override
-                    public boolean isSatisfied() {
-                        return popup.isShowing();
-                    }
-                }));
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria("Autofill Popup was never shown.") {
+            @Override
+            public boolean isSatisfied() {
+                return popup.isShowing();
+            }
+        });
     }
 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillTest.java
index 9c57cb3..42ec87c 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillTest.java
@@ -84,8 +84,8 @@
         public void deleteSuggestion(int listIndex) {
         }
 
-        public boolean waitForCallback() throws InterruptedException {
-            return CriteriaHelper.pollForCriteria(new Criteria() {
+        public void waitForCallback() throws InterruptedException {
+            CriteriaHelper.pollForCriteria(new Criteria() {
                 @Override
                 public boolean isSatisfied() {
                     return mGotPopupSelection.get();
@@ -117,7 +117,7 @@
         };
     }
 
-    public boolean openAutofillPopupAndWaitUntilReady(final AutofillSuggestion[] suggestions)
+    public void openAutofillPopupAndWaitUntilReady(final AutofillSuggestion[] suggestions)
             throws InterruptedException {
         ThreadUtils.runOnUiThreadBlocking(new Runnable() {
             @Override
@@ -125,7 +125,7 @@
                 mAutofillPopup.filterAndShow(suggestions, false);
             }
         });
-        return CriteriaHelper.pollForCriteria(new Criteria() {
+        CriteriaHelper.pollForCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return mAutofillPopup.getListView().getChildCount() > 0;
@@ -136,10 +136,10 @@
     @SmallTest
     @Feature({"autofill"})
     public void testAutofillWithDifferentNumberSuggestions() throws Exception {
-        assertTrue(openAutofillPopupAndWaitUntilReady(createTwoAutofillSuggestionArray()));
+        openAutofillPopupAndWaitUntilReady(createTwoAutofillSuggestionArray());
         assertEquals(2, mAutofillPopup.getListView().getCount());
 
-        assertTrue(openAutofillPopupAndWaitUntilReady(createFiveAutofillSuggestionArray()));
+        openAutofillPopupAndWaitUntilReady(createFiveAutofillSuggestionArray());
         assertEquals(5, mAutofillPopup.getListView().getCount());
     }
 
@@ -147,11 +147,11 @@
     @Feature({"autofill"})
     public void testAutofillClickFirstSuggestion() throws Exception {
         AutofillSuggestion[] suggestions = createTwoAutofillSuggestionArray();
-        assertTrue(openAutofillPopupAndWaitUntilReady(suggestions));
+        openAutofillPopupAndWaitUntilReady(suggestions);
         assertEquals(2, mAutofillPopup.getListView().getCount());
 
         TouchCommon.singleClickView(mAutofillPopup.getListView().getChildAt(0));
-        assertTrue(mMockAutofillCallback.waitForCallback());
+        mMockAutofillCallback.waitForCallback();
 
         assertEquals(0, mMockAutofillCallback.mListIndex);
     }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/banners/AppBannerManagerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/banners/AppBannerManagerTest.java
index 06d74ac..5749fe9 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/banners/AppBannerManagerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/banners/AppBannerManagerTest.java
@@ -189,8 +189,8 @@
         AppBannerManager.setEngagementWeights(1, 1);
     }
 
-    private boolean waitUntilNoInfoBarsExist() throws Exception {
-        return CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+    private void waitUntilNoInfoBarsExist() throws Exception {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 InfoBarContainer container = getActivity().getActivityTab().getInfoBarContainer();
@@ -199,8 +199,8 @@
         });
     }
 
-    private boolean waitUntilAppDetailsRetrieved(final int numExpected) throws Exception {
-        return CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+    private void waitUntilAppDetailsRetrieved(final int numExpected) throws Exception {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 AppBannerManager manager =
@@ -211,8 +211,8 @@
         });
     }
 
-    private boolean waitUntilAppBannerInfoBarAppears(final String title) throws Exception {
-        return CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+    private void waitUntilAppBannerInfoBarAppears(final String title) throws Exception {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 InfoBarContainer container = getActivity().getActivityTab().getInfoBarContainer();
@@ -231,9 +231,9 @@
     private void runFullNativeInstallPathway(String url, String expectedReferrer) throws Exception {
         // Visit a site that requests a banner.
         new TabLoadObserver(getActivity().getActivityTab(), url).assertLoaded();
-        assertTrue(waitUntilAppDetailsRetrieved(1));
+        waitUntilAppDetailsRetrieved(1);
         assertEquals(mDetailsDelegate.mReferrer, expectedReferrer);
-        assertTrue(waitUntilNoInfoBarsExist());
+        waitUntilNoInfoBarsExist();
 
         // Indicate a day has passed, then revisit the page to get the banner to appear.
         InfoBarContainer container = getActivity().getActivityTab().getInfoBarContainer();
@@ -241,14 +241,14 @@
         container.setAnimationListener(listener);
         AppBannerManager.setTimeDeltaForTesting(1);
         new TabLoadObserver(getActivity().getActivityTab(), url).assertLoaded();
-        assertTrue(waitUntilAppDetailsRetrieved(2));
-        assertTrue(waitUntilAppBannerInfoBarAppears(NATIVE_APP_TITLE));
-        assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        waitUntilAppDetailsRetrieved(2);
+        waitUntilAppBannerInfoBarAppears(NATIVE_APP_TITLE);
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return listener.mDoneAnimating;
             }
-        }));
+        });
 
         // Check that the button asks if the user wants to install the app.
         InfoBar infobar = container.getInfoBars().get(0);
@@ -266,24 +266,24 @@
         // Wait for the infobar to register that the app is installing.
         final String installingText =
                 getInstrumentation().getTargetContext().getString(R.string.app_banner_installing);
-        assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
+        CriteriaHelper.pollForCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return getInstrumentation().checkMonitorHit(activityMonitor, 1)
                         && TextUtils.equals(button.getText(), installingText);
             }
-        }));
+        });
 
         // Say that the package is installed.  Infobar should say that the app is ready to open.
         mPackageManager.isInstalled = true;
         final String openText =
                 getInstrumentation().getTargetContext().getString(R.string.app_banner_open);
-        assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
+        CriteriaHelper.pollForCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return TextUtils.equals(button.getText(), openText);
             }
-        }));
+        });
     }
 
     @SmallTest
@@ -303,42 +303,42 @@
     public void testBannerAppearsThenDoesNotAppearAgainForMonths() throws Exception {
         // Visit a site that requests a banner.
         new TabLoadObserver(getActivity().getActivityTab(), NATIVE_APP_URL).assertLoaded();
-        assertTrue(waitUntilAppDetailsRetrieved(1));
-        assertTrue(waitUntilNoInfoBarsExist());
+        waitUntilAppDetailsRetrieved(1);
+        waitUntilNoInfoBarsExist();
 
         // Indicate a day has passed, then revisit the page.
         AppBannerManager.setTimeDeltaForTesting(1);
         new TabLoadObserver(getActivity().getActivityTab(), NATIVE_APP_URL).assertLoaded();
-        assertTrue(waitUntilAppDetailsRetrieved(2));
-        assertTrue(waitUntilAppBannerInfoBarAppears(NATIVE_APP_TITLE));
+        waitUntilAppDetailsRetrieved(2);
+        waitUntilAppBannerInfoBarAppears(NATIVE_APP_TITLE);
 
         // Revisit the page to make the banner go away, but don't explicitly dismiss it.
         // This hides the banner for a few months.
         new TabLoadObserver(getActivity().getActivityTab(), NATIVE_APP_URL).assertLoaded();
-        assertTrue(waitUntilAppDetailsRetrieved(3));
-        assertTrue(waitUntilNoInfoBarsExist());
+        waitUntilAppDetailsRetrieved(3);
+        waitUntilNoInfoBarsExist();
 
         // Wait a month until revisiting the page.
         AppBannerManager.setTimeDeltaForTesting(31);
         new TabLoadObserver(getActivity().getActivityTab(), NATIVE_APP_URL).assertLoaded();
-        assertTrue(waitUntilAppDetailsRetrieved(4));
-        assertTrue(waitUntilNoInfoBarsExist());
+        waitUntilAppDetailsRetrieved(4);
+        waitUntilNoInfoBarsExist();
 
         AppBannerManager.setTimeDeltaForTesting(32);
         new TabLoadObserver(getActivity().getActivityTab(), NATIVE_APP_URL).assertLoaded();
-        assertTrue(waitUntilAppDetailsRetrieved(5));
-        assertTrue(waitUntilNoInfoBarsExist());
+        waitUntilAppDetailsRetrieved(5);
+        waitUntilNoInfoBarsExist();
 
         // Wait two months until revisiting the page, which should pop up the banner.
         AppBannerManager.setTimeDeltaForTesting(61);
         new TabLoadObserver(getActivity().getActivityTab(), NATIVE_APP_URL).assertLoaded();
-        assertTrue(waitUntilAppDetailsRetrieved(6));
-        assertTrue(waitUntilNoInfoBarsExist());
+        waitUntilAppDetailsRetrieved(6);
+        waitUntilNoInfoBarsExist();
 
         AppBannerManager.setTimeDeltaForTesting(62);
         new TabLoadObserver(getActivity().getActivityTab(), NATIVE_APP_URL).assertLoaded();
-        assertTrue(waitUntilAppDetailsRetrieved(7));
-        assertTrue(waitUntilAppBannerInfoBarAppears(NATIVE_APP_TITLE));
+        waitUntilAppDetailsRetrieved(7);
+        waitUntilAppBannerInfoBarAppears(NATIVE_APP_TITLE);
     }
 
     @MediumTest
@@ -346,8 +346,8 @@
     public void testBlockedBannerDoesNotAppearAgainForMonths() throws Exception {
         // Visit a site that requests a banner.
         new TabLoadObserver(getActivity().getActivityTab(), NATIVE_APP_URL).assertLoaded();
-        assertTrue(waitUntilAppDetailsRetrieved(1));
-        assertTrue(waitUntilNoInfoBarsExist());
+        waitUntilAppDetailsRetrieved(1);
+        waitUntilNoInfoBarsExist();
 
         // Indicate a day has passed, then revisit the page.
         InfoBarContainer container = getActivity().getActivityTab().getInfoBarContainer();
@@ -355,42 +355,42 @@
         container.setAnimationListener(listener);
         AppBannerManager.setTimeDeltaForTesting(1);
         new TabLoadObserver(getActivity().getActivityTab(), NATIVE_APP_URL).assertLoaded();
-        assertTrue(waitUntilAppDetailsRetrieved(2));
-        assertTrue(waitUntilAppBannerInfoBarAppears(NATIVE_APP_TITLE));
+        waitUntilAppDetailsRetrieved(2);
+        waitUntilAppBannerInfoBarAppears(NATIVE_APP_TITLE);
 
         // Explicitly dismiss the banner.
-        assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return listener.mDoneAnimating;
             }
-        }));
+        });
         ArrayList<InfoBar> infobars = container.getInfoBars();
         View close = infobars.get(0).getView().findViewById(R.id.infobar_close_button);
         TouchCommon.singleClickView(close);
-        assertTrue(waitUntilNoInfoBarsExist());
+        waitUntilNoInfoBarsExist();
 
         // Waiting two months shouldn't be long enough.
         AppBannerManager.setTimeDeltaForTesting(61);
         new TabLoadObserver(getActivity().getActivityTab(), NATIVE_APP_URL).assertLoaded();
-        assertTrue(waitUntilAppDetailsRetrieved(3));
-        assertTrue(waitUntilNoInfoBarsExist());
+        waitUntilAppDetailsRetrieved(3);
+        waitUntilNoInfoBarsExist();
 
         AppBannerManager.setTimeDeltaForTesting(62);
         new TabLoadObserver(getActivity().getActivityTab(), NATIVE_APP_URL).assertLoaded();
-        assertTrue(waitUntilAppDetailsRetrieved(4));
-        assertTrue(waitUntilNoInfoBarsExist());
+        waitUntilAppDetailsRetrieved(4);
+        waitUntilNoInfoBarsExist();
 
         // Waiting three months should allow banners to reappear.
         AppBannerManager.setTimeDeltaForTesting(91);
         new TabLoadObserver(getActivity().getActivityTab(), NATIVE_APP_URL).assertLoaded();
-        assertTrue(waitUntilAppDetailsRetrieved(5));
-        assertTrue(waitUntilNoInfoBarsExist());
+        waitUntilAppDetailsRetrieved(5);
+        waitUntilNoInfoBarsExist();
 
         AppBannerManager.setTimeDeltaForTesting(92);
         new TabLoadObserver(getActivity().getActivityTab(), NATIVE_APP_URL).assertLoaded();
-        assertTrue(waitUntilAppDetailsRetrieved(6));
-        assertTrue(waitUntilAppBannerInfoBarAppears(NATIVE_APP_TITLE));
+        waitUntilAppDetailsRetrieved(6);
+        waitUntilAppBannerInfoBarAppears(NATIVE_APP_TITLE);
     }
 
     @MediumTest
@@ -401,12 +401,12 @@
             new TabLoadObserver(getActivity().getActivityTab(), NATIVE_APP_URL).assertLoaded();
 
             final Integer iteration = Integer.valueOf(i);
-            assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+            CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
                 @Override
                 public boolean isSatisfied() {
                     return mDetailsDelegate.mNumRetrieved == iteration;
                 }
-            }));
+            });
         }
     }
 
@@ -417,28 +417,28 @@
         loadUrlInNewTab("about:blank");
         new TabLoadObserver(getActivity().getActivityTab(), WEB_APP_URL).assertLoaded();
 
-        assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 AppBannerManager manager =
                         getActivity().getActivityTab().getAppBannerManagerForTesting();
                 return !manager.isFetcherActiveForTesting();
             }
-        }));
-        assertTrue(waitUntilNoInfoBarsExist());
+        });
+        waitUntilNoInfoBarsExist();
 
         // Indicate a day has passed, then revisit the page to show the banner.
         AppBannerManager.setTimeDeltaForTesting(1);
         new TabLoadObserver(getActivity().getActivityTab(), WEB_APP_URL).assertLoaded();
-        assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 AppBannerManager manager =
                         getActivity().getActivityTab().getAppBannerManagerForTesting();
                 return !manager.isFetcherActiveForTesting();
             }
-        }));
-        assertTrue(waitUntilAppBannerInfoBarAppears(WEB_APP_TITLE));
+        });
+        waitUntilAppBannerInfoBarAppears(WEB_APP_TITLE);
     }
 
     @SmallTest
@@ -452,15 +452,15 @@
         loadUrlInNewTab("about:blank");
         new TabLoadObserver(getActivity().getActivityTab(), WEB_APP_URL).assertLoaded();
 
-        assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 AppBannerManager manager =
                         getActivity().getActivityTab().getAppBannerManagerForTesting();
                 return !manager.isFetcherActiveForTesting();
             }
-        }));
-        assertTrue(waitUntilNoInfoBarsExist());
+        });
+        waitUntilNoInfoBarsExist();
 
         // Add the animation listener in.
         InfoBarContainer container = getActivity().getActivityTab().getInfoBarContainer();
@@ -470,21 +470,21 @@
         // Indicate a day has passed, then revisit the page to show the banner.
         AppBannerManager.setTimeDeltaForTesting(1);
         new TabLoadObserver(getActivity().getActivityTab(), WEB_APP_URL).assertLoaded();
-        assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 AppBannerManager manager =
                         getActivity().getActivityTab().getAppBannerManagerForTesting();
                 return !manager.isFetcherActiveForTesting();
             }
-        }));
-        assertTrue(waitUntilAppBannerInfoBarAppears(WEB_APP_TITLE));
-        assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        });
+        waitUntilAppBannerInfoBarAppears(WEB_APP_TITLE);
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return listener.mDoneAnimating;
             }
-        }));
+        });
 
         // Click the button to trigger the adding of the shortcut.
         InfoBar infobar = container.getInfoBars().get(0);
@@ -493,12 +493,12 @@
         TouchCommon.singleClickView(button);
 
         // Make sure that the splash screen icon was downloaded.
-        assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return dataStorageFactory.mSplashImage != null;
             }
-        }));
+        });
 
         // Test that bitmap sizes match expectations.
         int idealSize = getActivity().getResources().getDimensionPixelSize(
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/banners/InstallerDelegateTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/banners/InstallerDelegateTest.java
index 779078fb..29a1c5fa 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/banners/InstallerDelegateTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/banners/InstallerDelegateTest.java
@@ -93,21 +93,21 @@
         mInstallStarted = true;
 
         // Wait until we know that the Thread is running the InstallerDelegate task.
-        assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
+        CriteriaHelper.pollForCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return mTestDelegate.isRunning();
             }
-        }));
+        });
     }
 
     private void checkResults(boolean expectedResult) throws InterruptedException {
-        assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
+        CriteriaHelper.pollForCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return !mTestDelegate.isRunning() && mResultFinished;
             }
-        }));
+        });
 
         assertEquals(expectedResult, mResultSuccess);
         assertEquals(mTestDelegate, mResultDelegate);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contextmenu/ContextMenuTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contextmenu/ContextMenuTest.java
index cc00414d..a7d39da9 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/contextmenu/ContextMenuTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contextmenu/ContextMenuTest.java
@@ -12,8 +12,6 @@
 import android.view.ContextMenu;
 import android.view.KeyEvent;
 
-import junit.framework.Assert;
-
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.base.test.util.DisabledTest;
@@ -156,13 +154,12 @@
         assertFalse("Context menu did not have window focus", getActivity().hasWindowFocus());
 
         getInstrumentation().sendKeyDownUpSync(KeyEvent.KEYCODE_BACK);
-        Assert.assertTrue("Activity did not regain focus.",
-                CriteriaHelper.pollForCriteria(new Criteria() {
-                    @Override
-                    public boolean isSatisfied() {
-                        return getActivity().hasWindowFocus();
-                    }
-                }));
+        CriteriaHelper.pollForCriteria(new Criteria("Activity did not regain focus.") {
+            @Override
+            public boolean isSatisfied() {
+                return getActivity().hasWindowFocus();
+            }
+        });
     }
 
     @MediumTest
@@ -175,13 +172,12 @@
 
         TestTouchUtils.singleClickView(getInstrumentation(), tab.getView(), 0, 0);
 
-        Assert.assertTrue("Activity did not regain focus.",
-                CriteriaHelper.pollForCriteria(new Criteria() {
-                    @Override
-                    public boolean isSatisfied() {
-                        return getActivity().hasWindowFocus();
-                    }
-                }));
+        CriteriaHelper.pollForCriteria(new Criteria("Activity did not regain focus.") {
+            @Override
+            public boolean isSatisfied() {
+                return getActivity().hasWindowFocus();
+            }
+        });
     }
 
     @MediumTest
@@ -247,13 +243,13 @@
         // Wait for any new tab animation to finish if we're being driven by the compositor.
         final LayoutManager layoutDriver = getActivity()
                 .getCompositorViewHolder().getLayoutManager();
-        assertTrue("Background tab animation not finished.",
-                CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(
+                new Criteria("Background tab animation not finished.") {
                     @Override
                     public boolean isSatisfied() {
                         return layoutDriver.getActiveLayout().shouldDisplayContentOverlay();
                     }
-                }));
+                });
 
         ContextMenuUtils.selectContextMenuItem(this, tab, "testLink2",
                 R.id.contextmenu_open_in_new_tab);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java
index 15a6814..456a007 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java
@@ -141,7 +141,7 @@
     public void longPressNode(String nodeId) throws InterruptedException, TimeoutException {
         Tab tab = getActivity().getActivityTab();
         DOMUtils.longPressNode(this, tab.getContentViewCore(), nodeId);
-        waitForPanelToPeekAndAssert();
+        waitForPanelToPeek();
     }
 
     /**
@@ -158,13 +158,12 @@
      * @param text The string to wait for the selection to become.
      */
     public void waitForSelectionToBe(final String text) throws InterruptedException {
-        assertTrue("Bar never showed desired text.",
-                CriteriaHelper.pollForCriteria(new Criteria() {
-                    @Override
-                    public boolean isSatisfied() {
-                        return TextUtils.equals(text, getSelectedText());
-                    }
-                }, TEST_TIMEOUT, DEFAULT_POLLING_INTERVAL));
+        CriteriaHelper.pollForCriteria(new Criteria("Bar never showed desired text.") {
+            @Override
+            public boolean isSatisfied() {
+                return TextUtils.equals(text, getSelectedText());
+            }
+        }, TEST_TIMEOUT, DEFAULT_POLLING_INTERVAL);
     }
 
     /**
@@ -173,13 +172,12 @@
      */
     public void waitForSearchTermResolutionToStart(
             final ContextualSearchFakeServer.FakeTapSearch search) throws InterruptedException {
-        assertTrue("Fake Search Term Resolution never started.",
-                CriteriaHelper.pollForCriteria(new Criteria() {
-                    @Override
-                    public boolean isSatisfied() {
-                        return search.didStartSearchTermResolution();
-                    }
-                }, TEST_TIMEOUT, DEFAULT_POLLING_INTERVAL));
+        CriteriaHelper.pollForCriteria(new Criteria("Fake Search Term Resolution never started.") {
+            @Override
+            public boolean isSatisfied() {
+                return search.didStartSearchTermResolution();
+            }
+        }, TEST_TIMEOUT, DEFAULT_POLLING_INTERVAL);
     }
 
     /**
@@ -188,13 +186,12 @@
      */
     public void waitForSearchTermResolutionToFinish(
             final ContextualSearchFakeServer.FakeTapSearch search) throws InterruptedException {
-        assertTrue("Fake Search was never ready.",
-                CriteriaHelper.pollForCriteria(new Criteria() {
-                    @Override
-                    public boolean isSatisfied() {
-                        return search.didFinishSearchTermResolution();
-                    }
-                }, TEST_TIMEOUT, DEFAULT_POLLING_INTERVAL));
+        CriteriaHelper.pollForCriteria(new Criteria("Fake Search was never ready.") {
+            @Override
+            public boolean isSatisfied() {
+                return search.didFinishSearchTermResolution();
+            }
+        }, TEST_TIMEOUT, DEFAULT_POLLING_INTERVAL);
     }
 
     /**
@@ -226,7 +223,7 @@
         ContextualSearchFakeServer.FakeLongPressSearch search =
                 mFakeServer.getFakeLongPressSearch(nodeId);
         search.simulate();
-        waitForPanelToPeekAndAssert();
+        waitForPanelToPeek();
     }
 
     /**
@@ -240,7 +237,7 @@
         ContextualSearchFakeServer.FakeTapSearch search = mFakeServer.getFakeTapSearch(nodeId);
         search.simulate();
         assertLoadedSearchTermMatches(search.getSearchTerm());
-        waitForPanelToPeekAndAssert();
+        waitForPanelToPeek();
     }
 
     /**
@@ -420,7 +417,7 @@
      */
     private void clickWordNode(String nodeId) throws InterruptedException, TimeoutException {
         clickNode(nodeId);
-        waitForPanelToPeekAndAssert();
+        waitForPanelToPeek();
     }
 
     /**
@@ -542,32 +539,32 @@
      * did peek.
      * @throws InterruptedException
      */
-    private void waitForPanelToPeekAndAssert() throws InterruptedException {
-        waitForPanelToEnterStateAndAssert(PanelState.PEEKED);
+    private void waitForPanelToPeek() throws InterruptedException {
+        waitForPanelToEnterState(PanelState.PEEKED);
     }
 
     /**
      * Waits for the Search Panel to expand, and asserts that it did expand.
      * @throws InterruptedException
      */
-    private void waitForPanelToExpandAndAssert() throws InterruptedException {
-        waitForPanelToEnterStateAndAssert(PanelState.EXPANDED);
+    private void waitForPanelToExpand() throws InterruptedException {
+        waitForPanelToEnterState(PanelState.EXPANDED);
     }
 
     /**
      * Waits for the Search Panel to maximize, and asserts that it did maximize.
      * @throws InterruptedException
      */
-    private void waitForPanelToMaximizeAndAssert() throws InterruptedException {
-        waitForPanelToEnterStateAndAssert(PanelState.MAXIMIZED);
+    private void waitForPanelToMaximize() throws InterruptedException {
+        waitForPanelToEnterState(PanelState.MAXIMIZED);
     }
 
     /**
      * Waits for the Search Panel to close, and asserts that it did close.
      * @throws InterruptedException
      */
-    private void waitForPanelToCloseAndAssert() throws InterruptedException {
-        waitForPanelToEnterStateAndAssert(PanelState.CLOSED);
+    private void waitForPanelToClose() throws InterruptedException {
+        waitForPanelToEnterState(PanelState.CLOSED);
     }
 
     /**
@@ -575,40 +572,24 @@
      * @throws InterruptedException
      */
     private void assertPanelNeverOpened() throws InterruptedException {
-        assertTrue(
-                "Search Panel actually did open.", waitForPanelToEnterState(PanelState.UNDEFINED));
-    }
-
-    /**
-     * Waits for the Search Panel to enter the given {@code PanelState}.
-     * @throws InterruptedException
-     */
-    private boolean waitForPanelToEnterState(final PanelState state) throws InterruptedException {
-        return CriteriaHelper.pollForCriteria(new Criteria() {
-            @Override
-            public boolean isSatisfied() {
-                return mPanel != null
-                        && mPanel.getPanelState() == state;
-            }
-        }, TEST_TIMEOUT, DEFAULT_POLLING_INTERVAL);
+        waitForPanelToEnterState(PanelState.UNDEFINED);
     }
 
     /**
      * Waits for the Search Panel to enter the given {@code PanelState} and assert.
      * @throws InterruptedException
      */
-    private void waitForPanelToEnterStateAndAssert(final PanelState state)
+    private void waitForPanelToEnterState(final PanelState state)
             throws InterruptedException {
-        boolean success =
-                CriteriaHelper.pollForCriteria(new Criteria() {
-                    @Override
-                    public boolean isSatisfied() {
-                        return mPanel != null
-                                && mPanel.getPanelState() == state;
-                    }
-                }, TEST_TIMEOUT, DEFAULT_POLLING_INTERVAL);
-        assertTrue("Panel did not enter " + state + " state. "
-                + "Instead, the current state is " + mPanel.getPanelState() + ".", success);
+        CriteriaHelper.pollForCriteria(new Criteria() {
+            @Override
+            public boolean isSatisfied() {
+                if (mPanel == null) return false;
+                updateFailureReason("Panel did not enter " + state + " state. "
+                        + "Instead, the current state is " + mPanel.getPanelState() + ".");
+                return mPanel.getPanelState() == state;
+            }
+        }, TEST_TIMEOUT, DEFAULT_POLLING_INTERVAL);
     }
 
     /**
@@ -616,14 +597,13 @@
      * Tells the manager that a gesture has started, and then waits for it to complete.
      * @throws InterruptedException
      */
-    private void waitForGestureProcessingAndAssert() throws InterruptedException {
-        assertTrue("Gesture processing did not complete.",
-                CriteriaHelper.pollForCriteria(new Criteria() {
-                    @Override
-                    public boolean isSatisfied() {
-                        return !mSelectionController.wasAnyTapGestureDetected();
-                    }
-                }, TEST_TIMEOUT, DEFAULT_POLLING_INTERVAL));
+    private void waitForGestureProcessing() throws InterruptedException {
+        CriteriaHelper.pollForCriteria(new Criteria("Gesture processing did not complete.") {
+            @Override
+            public boolean isSatisfied() {
+                return !mSelectionController.wasAnyTapGestureDetected();
+            }
+        }, TEST_TIMEOUT, DEFAULT_POLLING_INTERVAL);
     }
 
     /**
@@ -634,8 +614,8 @@
      * @throws InterruptedException
      */
     private void waitForGestureToClosePanelAndAssertNoSelection() throws InterruptedException {
-        waitForGestureProcessingAndAssert();
-        waitForPanelToCloseAndAssert();
+        waitForGestureProcessing();
+        waitForPanelToClose();
         assertPanelClosedOrUndefined();
         assertNull(getSelectedText());
     }
@@ -648,19 +628,19 @@
      * and a subsequent tap may think there's a current selection until it has been dissolved.
      */
     private void waitForSelectionDissolved() throws InterruptedException {
-        assertTrue("Selection never dissolved.", CriteriaHelper.pollForCriteria(new Criteria() {
+        CriteriaHelper.pollForCriteria(new Criteria("Selection never dissolved.") {
             @Override
             public boolean isSatisfied() {
                 return !mSelectionController.isSelectionEstablished();
             }
-        }, TEST_TIMEOUT, DEFAULT_POLLING_INTERVAL));
+        }, TEST_TIMEOUT, DEFAULT_POLLING_INTERVAL);
     }
 
     /**
      * Waits for the panel to close and then waits for the selection to dissolve.
      */
     private void waitForPanelToCloseAndSelectionDissolved() throws InterruptedException {
-        waitForPanelToCloseAndAssert();
+        waitForPanelToClose();
         waitForSelectionDissolved();
     }
 
@@ -755,7 +735,7 @@
         // long press and trying to close with the bar peeking, with a long press selection
         // established).
         tapBasePage(0.9f, 0.35f);
-        waitForPanelToCloseAndAssert();
+        waitForPanelToClose();
     }
 
     /**
@@ -806,7 +786,7 @@
      */
     private void tapPeekingBarToExpandAndAssert() throws InterruptedException {
         clickPanelBar(0.95f);
-        waitForPanelToExpandAndAssert();
+        waitForPanelToExpand();
     }
 
     /**
@@ -834,7 +814,7 @@
         clickWordNode("states");
         assertSearchTermRequested();
         fakeResponse(false, 200, "States", "display-text", "alternate-term", false);
-        waitForPanelToPeekAndAssert();
+        waitForPanelToPeek();
         clickNode("states-far");
         waitForPanelToCloseAndSelectionDissolved();
     }
@@ -848,7 +828,7 @@
         assertSearchTermRequested();
 
         fakeResponse(false, 200, "states", "United States Intelligence", "alternate-term", false);
-        waitForPanelToPeekAndAssert();
+        waitForPanelToPeek();
         assertLoadedLowPriorityUrl();
         assertContainsParameters("states", "alternate-term");
     }
@@ -893,7 +873,7 @@
         assertEquals("Intelligence", mFakeServer.getSearchTermRequested());
         fakeResponse(false, 200, "Intelligence", "display-text", "alternate-term", false);
         assertContainsParameters("Intelligence", "alternate-term");
-        waitForPanelToPeekAndAssert();
+        waitForPanelToPeek();
 
         OmniboxTestUtils.toggleUrlBarFocus((UrlBar) getActivity().findViewById(R.id.url_bar), true);
 
@@ -955,7 +935,7 @@
         assertEquals("Intelligence", mFakeServer.getSearchTermRequested());
         fakeResponse(false, 200, "Intelligence", "display-text", "alternate-term", false);
         assertContainsParameters("Intelligence", "alternate-term");
-        waitForPanelToPeekAndAssert();
+        waitForPanelToPeek();
         assertLoadedLowPriorityUrl();
     }
 
@@ -969,7 +949,7 @@
         longPressNode("states");
 
         assertNull(mFakeServer.getSearchTermRequested());
-        waitForPanelToPeekAndAssert();
+        waitForPanelToPeek();
         assertLoadedNoUrl();
         assertNoContentViewCore();
     }
@@ -992,9 +972,9 @@
         assertEquals(1, mFakeServer.getLoadedUrlCount());
         assertLoadedLowPriorityUrl();
 
-        waitForPanelToPeekAndAssert();
+        waitForPanelToPeek();
         flingPanelUp();
-        waitForPanelToExpandAndAssert();
+        waitForPanelToExpand();
         assertEquals(1, mFakeServer.getLoadedUrlCount());
         assertLoadedLowPriorityUrl();
     }
@@ -1019,11 +999,11 @@
                 false);
         assertContainsParameters("Intelligence", "alternate-term");
 
-        waitForPanelToPeekAndAssert();
+        waitForPanelToPeek();
         assertLoadedNoUrl();
         assertNoContentViewCore();
         flingPanelUp();
-        waitForPanelToExpandAndAssert();
+        waitForPanelToExpand();
         assertContentViewCoreCreated();
         assertLoadedNormalPriorityUrl();
         assertEquals(1, mFakeServer.getLoadedUrlCount());
@@ -1148,7 +1128,7 @@
         assertSearchTermRequested();
         fakeResponse(false, 200, "Intelligence", "display-text", "alternate-term", true);
         assertContainsNoParameters();
-        waitForPanelToPeekAndAssert();
+        waitForPanelToPeek();
         assertLoadedNoUrl();
     }
 
@@ -1163,10 +1143,10 @@
         assertEquals("Intelligence", getSelectedText());
         fakeResponse(false, 200, "Intelligence", "Intelligence", "alternate-term", false);
         assertContainsParameters("Intelligence", "alternate-term");
-        waitForPanelToPeekAndAssert();
+        waitForPanelToPeek();
         assertLoadedNoUrl();  // No load after long-press until opening panel.
         clickNode("question-mark");
-        waitForGestureProcessingAndAssert();
+        waitForGestureProcessing();
         assertNull(getSelectedText());
         assertPanelClosedOrUndefined();
         assertLoadedNoUrl();
@@ -1183,10 +1163,10 @@
         assertEquals("Intelligence", getSelectedText());
         fakeResponse(false, 200, "Intelligence", "Intelligence", "alternate-term", false);
         assertContainsParameters("Intelligence", "alternate-term");
-        waitForPanelToPeekAndAssert();
+        waitForPanelToPeek();
         assertLoadedLowPriorityUrl();
         clickNode("question-mark");
-        waitForGestureProcessingAndAssert();
+        waitForGestureProcessing();
         assertNull(getSelectedText());
     }
 
@@ -1199,7 +1179,7 @@
     public void testTapGestureOnSpecialCharacterDoesntSelect()
             throws InterruptedException, TimeoutException {
         clickNode("question-mark");
-        waitForGestureProcessingAndAssert();
+        waitForGestureProcessing();
         assertNull(getSelectedText());
         assertPanelClosedOrUndefined();
         assertLoadedNoUrl();
@@ -1216,7 +1196,7 @@
         clickWordNode("intelligence");
         fakeResponse(false, 200, "Intelligence", "Intelligence", "alternate-term", false);
         assertContainsParameters("Intelligence", "alternate-term");
-        waitForPanelToPeekAndAssert();
+        waitForPanelToPeek();
         assertLoadedLowPriorityUrl();
         scrollBasePage();
         assertPanelClosedOrUndefined();
@@ -1232,9 +1212,9 @@
     public void testTapGestureFollowedByInvalidTextTapCloses()
             throws InterruptedException, TimeoutException {
         clickWordNode("states-far");
-        waitForPanelToPeekAndAssert();
+        waitForPanelToPeek();
         clickNode("question-mark");
-        waitForGestureProcessingAndAssert();
+        waitForGestureProcessing();
         assertPanelClosedOrUndefined();
         assertNull(mSelectionController.getSelectedText());
     }
@@ -1249,9 +1229,9 @@
     public void testTapGestureFollowedByNonTextTap()
             throws InterruptedException, TimeoutException {
         clickWordNode("states-far");
-        waitForPanelToPeekAndAssert();
+        waitForPanelToPeek();
         clickNode("button");
-        waitForGestureProcessingAndAssert();
+        waitForGestureProcessing();
         assertPanelClosedOrUndefined();
         assertNull(mSelectionController.getSelectedText());
     }
@@ -1266,14 +1246,14 @@
             throws InterruptedException, TimeoutException {
         clickWordNode("states");
         assertEquals("States", getSelectedText());
-        waitForPanelToPeekAndAssert();
+        waitForPanelToPeek();
         clickNode("states-far");
-        waitForGestureProcessingAndAssert();
+        waitForGestureProcessing();
         assertNull(getSelectedText());
         assertPanelClosedOrUndefined();
         clickNode("states-far");
-        waitForGestureProcessingAndAssert();
-        waitForPanelToPeekAndAssert();
+        waitForGestureProcessing();
+        waitForPanelToPeek();
         assertEquals("States", getSelectedText());
     }
 
@@ -1287,7 +1267,7 @@
             throws InterruptedException, TimeoutException {
         clickWordNode("states");
         assertEquals("States", getSelectedText());
-        waitForPanelToPeekAndAssert();
+        waitForPanelToPeek();
         // Avoid issues with double-tap detection by ensuring sequential taps
         // aren't treated as such. Double-tapping can also select words much as
         // longpress, in turn showing the pins and preventing contextual tap
@@ -1313,7 +1293,7 @@
     public void testLongPressGestureFollowedByScrollMaintainsSelection()
             throws InterruptedException, TimeoutException {
         longPressNode("intelligence");
-        waitForPanelToPeekAndAssert();
+        waitForPanelToPeek();
         scrollBasePage();
         assertPanelClosedOrUndefined();
         assertEquals("Intelligence", getSelectedText());
@@ -1329,7 +1309,7 @@
     public void testLongPressGestureFollowedByTapDoesntSelect()
             throws InterruptedException, TimeoutException {
         longPressNode("intelligence");
-        waitForPanelToPeekAndAssert();
+        waitForPanelToPeek();
         clickWordNode("states-far");
         waitForGestureToClosePanelAndAssertNoSelection();
         assertLoadedNoUrl();
@@ -1345,7 +1325,7 @@
             throws InterruptedException, TimeoutException {
         clickWordNode("states");
         assertEquals("States", getSelectedText());
-        waitForPanelToPeekAndAssert();
+        waitForPanelToPeek();
 
         ThreadUtils.runOnUiThread(new Runnable() {
             @Override
@@ -1389,7 +1369,7 @@
 
         clickWordNode("states");
         assertEquals("States", getSelectedText());
-        waitForPanelToPeekAndAssert();
+        waitForPanelToPeek();
 
         ThreadUtils.runOnUiThread(new Runnable() {
             @Override
@@ -1398,16 +1378,7 @@
             }
         });
 
-        // Give the panelState time to change
-        CriteriaHelper.pollForCriteria(new Criteria(){
-            @Override
-            public boolean isSatisfied() {
-                PanelState panelState = mPanel.getPanelState();
-                return panelState != PanelState.PEEKED;
-            }
-        });
-
-        waitForPanelToPeekAndAssert();
+        waitForPanelToPeek();
     }
 
     /*
@@ -1426,11 +1397,11 @@
         assertSearchTermRequested();
 
         // Wait for the panel to peek.
-        waitForPanelToPeekAndAssert();
+        waitForPanelToPeek();
 
         // Swipe Panel up and wait for it to maximize.
         flingPanelUpToTop();
-        waitForPanelToMaximizeAndAssert();
+        waitForPanelToMaximize();
 
         // Create an observer to track that a new tab is created.
         final CallbackHelper tabCreatedHelper = new CallbackHelper();
@@ -1448,7 +1419,7 @@
 
         // The Search Term Resolution response hasn't arrived yet, so the Panel should not
         // be promoted. Therefore, we are asserting that the Panel is still maximized.
-        waitForPanelToMaximizeAndAssert();
+        waitForPanelToMaximize();
 
         // Get a Search Term Resolution response.
         fakeResponse(false, 200, "Intelligence", "display-text", "alternate-term", false);
@@ -1459,7 +1430,7 @@
 
         // Now that the response has arrived, tapping on the Search Panel should promote it
         // to a Tab. Therefore, we are asserting that the Panel got closed.
-        waitForPanelToCloseAndAssert();
+        waitForPanelToClose();
 
         // Finally, make sure a tab was created.
         if (!FeatureUtilities.isDocumentMode(getInstrumentation().getContext())) {
@@ -1631,7 +1602,7 @@
 
         // A long-press should still show the promo bar.
         longPressNode("states");
-        waitForPanelToPeekAndAssert();
+        waitForPanelToPeek();
 
         // Expanding the panel should deactivate the limit.
         tapBarToExpandAndClosePanel();
@@ -1789,14 +1760,14 @@
      * Asserts whether the App Menu is visible.
      */
     private void assertAppMenuVisibility(final boolean isVisible) throws InterruptedException {
-        assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
+        CriteriaHelper.pollForCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 if (getActivity()
                         .getAppMenuHandler().isAppMenuShowing() == isVisible) return true;
                 return false;
             }
-        }));
+        });
     }
 
     /**
@@ -1827,13 +1798,13 @@
     public void testAppMenuSuppressedWhenMaximized() throws InterruptedException, TimeoutException {
         clickWordNode("states");
         flingPanelUpToTop();
-        waitForPanelToMaximizeAndAssert();
+        waitForPanelToMaximize();
 
         pressAppMenuKey();
         assertAppMenuVisibility(false);
 
         pressBackButton();
-        waitForPanelToCloseAndAssert();
+        waitForPanelToClose();
 
         pressAppMenuKey();
         assertAppMenuVisibility(true);
@@ -2016,13 +1987,13 @@
 
     private void assertWaitForSelectActionBarVisible(final boolean visible)
             throws InterruptedException {
-        assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return visible == getActivity().getActivityTab().getContentViewCore()
                         .isSelectActionBarShowing();
             }
-        }));
+        });
     }
 
     /**
@@ -2050,7 +2021,7 @@
         });
         assertWaitForSelectActionBarVisible(false);
 
-        waitForPanelToCloseAndAssert();
+        waitForPanelToClose();
         assertEquals(1, observer.hideCount);
     }
 
@@ -2065,7 +2036,7 @@
     public void testPreventHandlingCurrentSelectionModification()
             throws InterruptedException, TimeoutException {
         longPressNode("intelligence");
-        waitForPanelToPeekAndAssert();
+        waitForPanelToPeek();
 
         // Dismiss the Contextual Search panel.
         scrollBasePage();
@@ -2079,7 +2050,7 @@
 
         // Select a different word and assert that the panel has appeared.
         longPressNode("states-far");
-        waitForPanelToPeekAndAssert();
+        waitForPanelToPeek();
     }
 
     /**
@@ -2193,7 +2164,7 @@
             throws InterruptedException, TimeoutException {
         mFakeServer.reset();
         clickWordNode("intelligence");
-        waitForPanelToPeekAndAssert();
+        waitForPanelToPeek();
 
         fakeResponse(false, 200, "Intelligence", "United States Intelligence", "alternate-term",
                 false, -14, 0, "");
@@ -2218,12 +2189,12 @@
 
         // Long press and make sure the Promo shows.
         longPressNode("intelligence");
-        waitForPanelToPeekAndAssert();
+        waitForPanelToPeek();
         assertTrue(mPanel.isPeekPromoVisible());
 
         // After expanding the Panel the Promo should be invisible.
         flingPanelUp();
-        waitForPanelToExpandAndAssert();
+        waitForPanelToExpand();
         assertFalse(mPanel.isPeekPromoVisible());
 
         // After closing the Panel the Promo should still be invisible.
@@ -2236,7 +2207,7 @@
 
         // Now that the Panel was opened at least once, the Promo should not show again.
         longPressNode("intelligence");
-        waitForPanelToPeekAndAssert();
+        waitForPanelToPeek();
         assertFalse(mPanel.isPeekPromoVisible());
     }
 
@@ -2307,7 +2278,7 @@
 
         // Swiping the Panel down should not change the visibility or load content again.
         swipePanelDown();
-        waitForPanelToPeekAndAssert();
+        waitForPanelToPeek();
         assertContentViewCoreVisible();
         assertEquals(1, mFakeServer.getLoadedUrlCount());
 
@@ -2343,7 +2314,7 @@
 
         // Swiping the Panel down should not change the visibility or load content again.
         swipePanelDown();
-        waitForPanelToPeekAndAssert();
+        waitForPanelToPeek();
         assertContentViewCoreVisible();
         assertEquals(1, mFakeServer.getLoadedUrlCount());
 
@@ -2418,7 +2389,7 @@
 
         // Swiping the Panel down should not change the visibility or load content again.
         swipePanelDown();
-        waitForPanelToPeekAndAssert();
+        waitForPanelToPeek();
         assertContentViewCoreVisible();
         assertEquals(1, mFakeServer.getLoadedUrlCount());
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchPolicyTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchPolicyTest.java
new file mode 100644
index 0000000..96ec178
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchPolicyTest.java
@@ -0,0 +1,71 @@
+// 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.contextualsearch;
+
+import android.test.suitebuilder.annotation.SmallTest;
+
+import org.chromium.base.test.util.Feature;
+import org.chromium.chrome.test.ChromeTabbedActivityTestBase;
+
+import java.util.ArrayList;
+
+/**
+ * Tests for the ContextualSearchPolicy class.
+ */
+public class ContextualSearchPolicyTest extends ChromeTabbedActivityTestBase {
+    ContextualSearchPolicy mPolicy;
+
+    @Override
+    public void startMainActivity() throws InterruptedException {
+        startMainActivityOnBlankPage();
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                mPolicy = ContextualSearchPolicy.getInstance(getActivity().getApplicationContext());
+            }
+        });
+    }
+
+    @SmallTest
+    @Feature({"ContextualSearch"})
+    public void testBestTargetLanguageFromMultiple() {
+        ArrayList<String> list = new ArrayList<String>();
+        list.add("br");
+        list.add("de");
+        assertEquals("br", mPolicy.bestTargetLanguage(list));
+    }
+
+    @SmallTest
+    @Feature({"ContextualSearch"})
+    public void testBestTargetLanguageSkipsEnglish() {
+        ArrayList<String> list = new ArrayList<String>();
+        list.add("en");
+        list.add("de");
+        assertEquals("de", mPolicy.bestTargetLanguage(list));
+    }
+
+    @SmallTest
+    @Feature({"ContextualSearch"})
+    public void testBestTargetLanguageUsesEnglishWhenOnlyChoice() {
+        ArrayList<String> list = new ArrayList<String>();
+        list.add("en");
+        assertEquals("en", mPolicy.bestTargetLanguage(list));
+    }
+
+    @SmallTest
+    @Feature({"ContextualSearch"})
+    public void testBestTargetLanguageReturnsEmptyWhenNoChoice() {
+        ArrayList<String> list = new ArrayList<String>();
+        assertEquals("", mPolicy.bestTargetLanguage(list));
+    }
+
+    // TODO(donnd): This set of tests is not complete, add more tests.
+}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/crash/MinidumpUploadServiceTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/crash/MinidumpUploadServiceTest.java
index 407c2549..2ce4ea1 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/crash/MinidumpUploadServiceTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/crash/MinidumpUploadServiceTest.java
@@ -320,18 +320,17 @@
         service.onHandleIntent(uploadIntent);
 
         // Verify asynchronously.
-        assertTrue("All callables should have a call-count of 1",
-                CriteriaHelper.pollForCriteria(new Criteria() {
-                    @Override
-                    public boolean isSatisfied() {
-                        for (CountedMinidumpUploadCallable callable : callables) {
-                            if (callable.mCalledCount != 1) {
-                                return false;
-                            }
-                        }
-                        return true;
+        CriteriaHelper.pollForCriteria(new Criteria("All callables should have a call-count of 1") {
+            @Override
+            public boolean isSatisfied() {
+                for (CountedMinidumpUploadCallable callable : callables) {
+                    if (callable.mCalledCount != 1) {
+                        return false;
                     }
-                }, MAX_TIMEOUT_MS, CHECK_INTERVAL_MS));
+                }
+                return true;
+            }
+        }, MAX_TIMEOUT_MS, CHECK_INTERVAL_MS);
     }
 
     /**
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java
index e37e82ec..b68e047 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java
@@ -165,12 +165,12 @@
             }
         });
 
-        assertTrue("App menu was not shown", CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria("App menu was not shown") {
             @Override
             public boolean isSatisfied() {
                 return mActivity.getAppMenuHandler().isAppMenuShowing();
             }
-        }));
+        });
     }
 
     /**
@@ -301,12 +301,12 @@
             }
         });
 
-        assertTrue("Pending Intent was not sent.", CriteriaHelper.pollForCriteria(new Criteria() {
+        CriteriaHelper.pollForCriteria(new Criteria("Pending Intent was not sent.") {
             @Override
             public boolean isSatisfied() {
                 return onFinished.isSent();
             }
-        }));
+        });
     }
 
     /**
@@ -338,14 +338,14 @@
         final ChromeActivity chromeActivity = (ChromeActivity) monitor
                 .waitForActivityWithTimeout(ACTIVITY_START_TIMEOUT_MS);
         assertNotNull("A normal chrome activity did not start.", chromeActivity);
-        assertTrue("The normal tab was not initiated correctly.",
-                CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(
+                new Criteria("The normal tab was not initiated correctly.") {
                     @Override
                     public boolean isSatisfied() {
                         Tab tab = chromeActivity.getActivityTab();
                         return tab != null && tab.getUrl().equals(TEST_PAGE);
                     }
-                }));
+                });
     }
 
     /**
@@ -409,12 +409,12 @@
             }
         });
 
-        assertTrue("Pending Intent was not sent.", CriteriaHelper.pollForCriteria(new Criteria() {
+        CriteriaHelper.pollForCriteria(new Criteria("Pending Intent was not sent.") {
             @Override
             public boolean isSatisfied() {
                 return onFinished.isSent();
             }
-        }));
+        });
     }
 
     /**
@@ -468,12 +468,12 @@
                                         (new CustomTabsTestUtils.DummyCallback()).asBinder()));
                     }
                 }));
-        assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
-                    @Override
-                    public boolean isSatisfied() {
-                        return mActivity.getActivityTab().getUrl().equals(TEST_PAGE);
-                    }
-        }));
+        CriteriaHelper.pollForCriteria(new Criteria() {
+            @Override
+            public boolean isSatisfied() {
+                return mActivity.getActivityTab().getUrl().equals(TEST_PAGE);
+            }
+        });
         assertTrue("CustomTabContentHandler can't handle intent with same session",
                 ThreadUtils.runOnUiThreadBlockingNoException(new Callable<Boolean>() {
                     @Override
@@ -496,12 +496,12 @@
         } catch (TimeoutException e) {
             fail();
         }
-        assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
-                    @Override
-                    public boolean isSatisfied() {
-                        return mActivity.getActivityTab().getUrl().equals(TEST_PAGE_2);
-                    }
-        }));
+        CriteriaHelper.pollForCriteria(new Criteria() {
+            @Override
+            public boolean isSatisfied() {
+                return mActivity.getActivityTab().getUrl().equals(TEST_PAGE_2);
+            }
+        });
     }
 
     @SmallTest
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTestBase.java b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTestBase.java
index b4b113f1..181276c 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTestBase.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTestBase.java
@@ -51,13 +51,12 @@
      */
     protected void startCustomTabActivityWithIntent(Intent intent) throws InterruptedException {
         startActivityCompletely(intent);
-        assertTrue("Tab never selected/initialized.",
-                CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
-                    @Override
-                    public boolean isSatisfied() {
-                        return getActivity().getActivityTab() != null;
-                    }
-                }));
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria("Tab never selected/initialized.") {
+            @Override
+            public boolean isSatisfied() {
+                return getActivity().getActivityTab() != null;
+            }
+        });
         final Tab tab = getActivity().getActivityTab();
         final CallbackHelper pageLoadFinishedHelper = new CallbackHelper();
         tab.addObserver(new EmptyTabObserver() {
@@ -71,13 +70,12 @@
         } catch (TimeoutException e) {
             fail();
         }
-        assertTrue("Deferred startup never completed",
-                CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
-                    @Override
-                    public boolean isSatisfied() {
-                        return DeferredStartupHandler.getInstance().isDeferredStartupComplete();
-                    }
-                }, 5000, 200));
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria("Deferred startup never completed") {
+            @Override
+            public boolean isSatisfied() {
+                return DeferredStartupHandler.getInstance().isDeferredStartupComplete();
+            }
+        }, 5000, 200);
         assertNotNull(tab);
         assertNotNull(tab.getView());
     }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/document/DocumentModeReferrerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/document/DocumentModeReferrerTest.java
index b583fc29..ce05191 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/document/DocumentModeReferrerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/document/DocumentModeReferrerTest.java
@@ -51,12 +51,12 @@
         ApplicationTestUtils.launchChrome(mContext);
 
         // Wait for tab model to become initialized.
-        assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
+        CriteriaHelper.pollForCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return ChromeApplication.isDocumentTabModelSelectorInitializedForTests();
             }
-        }));
+        });
 
         DocumentTabModelSelector selector = ChromeApplication.getDocumentTabModelSelector();
         mObserver = new TabModelSelectorTabObserver(selector) {
@@ -86,12 +86,12 @@
         IntentHandler.addTrustedIntentExtras(intent, mContext);
         mContext.startActivity(intent);
 
-        assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return URL_1.equals(mUrl);
             }
-        }));
+        });
 
         assertEquals(URL_2, mReferrer);
     }
@@ -103,12 +103,12 @@
         ApplicationTestUtils.launchChrome(mContext);
 
         // Wait for tab model to become initialized.
-        assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
+        CriteriaHelper.pollForCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return ChromeApplication.isDocumentTabModelSelectorInitializedForTests();
             }
-        }));
+        });
 
         DocumentTabModelSelector selector = ChromeApplication.getDocumentTabModelSelector();
         mObserver = new TabModelSelectorTabObserver(selector) {
@@ -138,12 +138,12 @@
         intent.putExtra(Intent.EXTRA_REFERRER, Uri.parse(androidAppReferrer));
         mContext.startActivity(intent);
 
-        assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return URL_1.equals(mUrl);
             }
-        }));
+        });
 
         assertEquals(androidAppReferrer, mReferrer);
     }
@@ -155,12 +155,12 @@
         ApplicationTestUtils.launchChrome(mContext);
 
         // Wait for tab model to become initialized.
-        assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
+        CriteriaHelper.pollForCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return ChromeApplication.isDocumentTabModelSelectorInitializedForTests();
             }
-        }));
+        });
 
         DocumentTabModelSelector selector = ChromeApplication.getDocumentTabModelSelector();
         mObserver = new TabModelSelectorTabObserver(selector) {
@@ -190,12 +190,12 @@
         intent.putExtra(Intent.EXTRA_REFERRER, Uri.parse(nonAppExtra));
         mContext.startActivity(intent);
 
-        assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return URL_1.equals(mUrl);
             }
-        }));
+        });
 
         // Check that referrer is not carried over
         assertNull(mReferrer);
@@ -208,12 +208,12 @@
         ApplicationTestUtils.launchChrome(mContext);
 
         // Wait for tab model to become initialized.
-        assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
+        CriteriaHelper.pollForCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return ChromeApplication.isDocumentTabModelSelectorInitializedForTests();
             }
-        }));
+        });
 
         DocumentTabModelSelector selector = ChromeApplication.getDocumentTabModelSelector();
         mObserver = new TabModelSelectorTabObserver(selector) {
@@ -244,12 +244,12 @@
         IntentHandler.setPendingReferrer(intent, "http://www.google.com");
         mContext.startActivity(intent);
 
-        assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return URL_1.equals(mUrl);
             }
-        }));
+        });
 
         // Check that referrer is not carried over
         assertEquals("http://www.google.com", mReferrer);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/document/DocumentModeTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/document/DocumentModeTest.java
index c596374..67b96e33 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/document/DocumentModeTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/document/DocumentModeTest.java
@@ -92,7 +92,7 @@
         startTabbedActivity(URL_1);
 
         // ApplicationStatus should note that the ChromeTabbedActivity isn't running anymore.
-        assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 List<WeakReference<Activity>> activities = ApplicationStatus.getRunningActivities();
@@ -101,7 +101,7 @@
                 }
                 return true;
             }
-        }));
+        });
     }
 
     /**
@@ -126,22 +126,22 @@
 
         // A DocumentActivity gets started, but it should immediately call finishAndRemoveTask()
         // because of the broken Intent.
-        assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 Activity activity = ApplicationStatus.getLastTrackedFocusedActivity();
                 return activity != lastTrackedActivity;
             }
-        }));
+        });
 
         // We shouldn't record that a new Tab exists.
-        assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return selector.getCurrentModel().getCount() == 3
                         && selector.getTotalTabCount() == 3;
             }
-        }));
+        });
     }
 
     /**
@@ -167,7 +167,7 @@
         // Funnily enough, Android doesn't differentiate between URIs with different queries when
         // refocusing Activities based on the Intent data.  This means we can't do a check to see
         // that the new Activity appears with URL_4 -- we just get a new instance of URL_3.
-        assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 Activity activity = ApplicationStatus.getLastTrackedFocusedActivity();
@@ -179,16 +179,16 @@
                         && !selector.isIncognitoSelected()
                         && lastTabId == selector.getCurrentTabId();
             }
-        }));
+        });
 
         // Although we get a new DocumentActivity, the old one with the same tab ID gets killed.
-        assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return selector.getCurrentModel().getCount() == 3
                     && selector.getTotalTabCount() == 3;
             }
-        }));
+        });
     }
 
     /**
@@ -212,14 +212,14 @@
         mContext.startActivity(intent);
         ApplicationTestUtils.waitUntilChromeInForeground();
 
-        assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
+        CriteriaHelper.pollForCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return lastTrackedActivity == ApplicationStatus.getLastTrackedFocusedActivity()
                         && !selector.isIncognitoSelected()
                         && lastTabId == selector.getCurrentTabId();
             }
-        }));
+        });
 
         assertEquals(3, selector.getCurrentModel().getCount());
         assertEquals(3, selector.getTotalTabCount());
@@ -241,12 +241,12 @@
         ApplicationTestUtils.fireHomeScreenIntent(mContext);
         ApplicationTestUtils.launchChrome(mContext);
 
-        assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
+        CriteriaHelper.pollForCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return !selector.isIncognitoSelected() && lastTabId == selector.getCurrentTabId();
             }
-        }));
+        });
 
         assertEquals(3, selector.getCurrentModel().getCount());
         assertEquals(3, selector.getTotalTabCount());
@@ -268,12 +268,12 @@
             }
         });
 
-        assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
+        CriteriaHelper.pollForCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return !selector.isIncognitoSelected() && selector.getCurrentModel().index() == 0;
             }
-        }));
+        });
 
         assertEquals(3, selector.getCurrentModel().getCount());
         assertEquals(3, selector.getTotalTabCount());
@@ -304,25 +304,25 @@
         };
         ActivityUtils.waitForActivity(getInstrumentation(), ChromeLauncherActivity.class, runnable);
         ApplicationTestUtils.waitUntilChromeInForeground();
-        assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 Activity lastActivity = ApplicationStatus.getLastTrackedFocusedActivity();
                 return lastActivity instanceof DocumentActivity;
             }
-        }));
+        });
         assertEquals(tabId, selector.getCurrentTabId());
         assertFalse(selector.isIncognitoSelected());
 
         // Create another tab.
         final int secondTabId = launchViaViewIntent(false, URL_2, "Page 2");
-        assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return selector.getModel(false).getCount() == 2
                         && selector.getCurrentTabId() == secondTabId;
             }
-        }));
+        });
     }
 
     /**
@@ -358,45 +358,45 @@
         final DocumentTabModelSelector selector =
                 ChromeApplication.getDocumentTabModelSelector();
         final TabModel incognitoModel = selector.getModel(true);
-        assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return firstId == selector.getCurrentTabId() && selector.getTotalTabCount() == 1;
             }
-        }));
+        });
         assertEquals(incognitoModel, selector.getCurrentModel());
 
         // Make sure the URL isn't in the Intent of the first IncognitoDocumentActivity.
-        assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return ApplicationStatus.getLastTrackedFocusedActivity()
                         instanceof IncognitoDocumentActivity;
             }
-        }));
+        });
         assertNull("URL is in the Incognito Intent", IntentHandler.getUrlFromIntent(
                 ApplicationStatus.getLastTrackedFocusedActivity().getIntent()));
 
         // Launch via ChromeLauncherActivity.launchInstance().
         final int secondId = launchViaLaunchDocumentInstance(true, URL_3, "Page 3");
-        assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return secondId == selector.getCurrentTabId() && selector.getTotalTabCount() == 2;
             }
-        }));
+        });
         assertTrue(selector.isIncognitoSelected());
         assertEquals(incognitoModel, selector.getCurrentModel());
         assertEquals(secondId, TabModelUtils.getCurrentTabId(incognitoModel));
 
         // Make sure the URL isn't in the Intent of the second IncognitoDocumentActivity.
-        assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return ApplicationStatus.getLastTrackedFocusedActivity()
                         instanceof IncognitoDocumentActivity;
             }
-        }));
+        });
         assertNull("URL is in the Incognito Intent", IntentHandler.getUrlFromIntent(
                 ApplicationStatus.getLastTrackedFocusedActivity().getIntent()));
     }
@@ -414,12 +414,12 @@
         final DocumentTabModelSelector selector =
                 ChromeApplication.getDocumentTabModelSelector();
         final TabModel incognitoModel = selector.getModel(true);
-        assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return firstId == selector.getCurrentTabId() && selector.getTotalTabCount() == 1;
             }
-        }));
+        });
         assertEquals(incognitoModel, selector.getCurrentModel());
 
         Activity firstActivity = ApplicationStatus.getLastTrackedFocusedActivity();
@@ -428,12 +428,12 @@
         // The context menu for links in Incognito mode lacks an "Open in new Incognito tab" option.
         // Instead, the regular "Open in new tab" option opens a new incognito tab.
         openLinkInNewTabViaContextMenu(false, true);
-        assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return firstId == selector.getCurrentTabId() && selector.getTotalTabCount() == 2;
             }
-        }));
+        });
         assertEquals(incognitoModel, selector.getCurrentModel());
         assertEquals(firstActivity, ApplicationStatus.getLastTrackedFocusedActivity());
     }
@@ -450,12 +450,12 @@
         assertFalse(selector.isIncognitoSelected());
 
         final int incognitoId = launchViaLaunchDocumentInstance(true, URL_2, "Page 2");
-        assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return selector.isIncognitoSelected() && selector.getCurrentTabId() == incognitoId;
             }
-        }));
+        });
         assertEquals(0, selector.getCurrentModel().index());
         assertEquals(1, selector.getCurrentModel().getCount());
 
@@ -463,12 +463,12 @@
                 ChromeLauncherActivity.getRemoveAllIncognitoTabsIntent(mContext);
         closeAllIntent.send();
 
-        assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return selector.getCurrentTabId() == regularId;
             }
-        }));
+        });
         OffTheRecordDocumentTabModel tabModel =
                 (OffTheRecordDocumentTabModel) selector.getModel(true);
         assertFalse(selector.isIncognitoSelected());
@@ -510,13 +510,13 @@
 
         // Re-open the other tab.
         TabModelUtils.setIndex(regularTabModel, 0);
-        assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return !selector.isIncognitoSelected()
                         && selector.getCurrentTabId() == regularTabId;
             }
-        }));
+        });
 
         // Try to open a new Incognito Tab in the background using the TabModelSelector directly.
         // Should open it in the foreground, instead.
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/document/DocumentModeTestBase.java b/chrome/android/javatests/src/org/chromium/chrome/browser/document/DocumentModeTestBase.java
index d4fc773b..7b33af79 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/document/DocumentModeTestBase.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/document/DocumentModeTestBase.java
@@ -165,7 +165,7 @@
         ApplicationTestUtils.waitUntilChromeInForeground();
 
         // Wait until the selector is ready and the Tabs have been added to the DocumentTabModel.
-        assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
+        CriteriaHelper.pollForCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 if (!ChromeApplication.isDocumentTabModelSelectorInitializedForTests()) {
@@ -179,7 +179,7 @@
                 if (selector.getCurrentTabId() == tabId) return false;
                 return true;
             }
-        }));
+        });
 
         if (launchedInBackground) {
             ChromeTabUtils.waitForTabPageLoaded(newActivity.getActivityTab(), (String) null);
@@ -206,7 +206,7 @@
 
         openLinkInNewTabViaContextMenu(false, false);
 
-        assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 if (expectedTabCount != tabModel.getCount()) return false;
@@ -214,7 +214,7 @@
                 if (expectedTabId != selector.getCurrentTabId()) return false;
                 return true;
             }
-        }));
+        });
 
         assertEquals(expectedActivity, ApplicationStatus.getLastTrackedFocusedActivity());
     }
@@ -250,12 +250,12 @@
             }
         });
         TouchCommon.longPressView(view);
-        assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return observer.mContextMenu != null;
             }
-        }));
+        });
         activity.getActivityTab().removeObserver(observer);
 
         // Select the "open in new tab" option.
@@ -287,7 +287,7 @@
     protected void switchToTab(final DocumentTab tab) throws Exception {
         final TabModel tabModel =
                 ChromeApplication.getDocumentTabModelSelector().getCurrentModel();
-        assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
+        CriteriaHelper.pollForCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 // http://crbug.com/509866: TabModelUtils#setIndex() sometimes fails.
@@ -304,7 +304,7 @@
                 if (activity == null) return false;
                 return ApplicationStatus.getStateForActivity(activity) == ActivityState.RESUMED;
             }
-        }));
+        });
     }
 
     /**
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/document/LauncherActivityTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/document/LauncherActivityTest.java
index 1a006a1..913c952 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/document/LauncherActivityTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/document/LauncherActivityTest.java
@@ -41,13 +41,13 @@
         mContext.startActivity(intent);
 
         // Check that Chrome launched successfully
-        assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
+        CriteriaHelper.pollForCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 int state = ApplicationStatus.getStateForApplication();
                 return state == ApplicationState.HAS_RUNNING_ACTIVITIES;
             }
-        }));
+        });
     }
 
     @Override
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/dom_distiller/ReaderModeManagerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/dom_distiller/ReaderModeManagerTest.java
index 0a7d394a..6d590bd 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/dom_distiller/ReaderModeManagerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/dom_distiller/ReaderModeManagerTest.java
@@ -55,13 +55,15 @@
         private int mPanelHideCount;
 
         @Override
-        public void requestPanelShow(OverlayPanel p, StateChangeReason r) {
+        public void requestPanelShow(OverlayPanel panel, StateChangeReason reason) {
             mRequestPanelShowCount++;
+            super.requestPanelShow(panel, reason);
         }
 
         @Override
-        public void notifyPanelClosed(OverlayPanel p, StateChangeReason r) {
+        public void notifyPanelClosed(OverlayPanel panel, StateChangeReason reason) {
             mPanelHideCount++;
+            super.notifyPanelClosed(panel, reason);
         }
 
         public int getRequestPanelShowCount() {
@@ -162,12 +164,14 @@
     @SmallTest
     @Feature({"ReaderModeManager"})
     public void testInfoBarEvents() {
+        mPanel.requestPanelShow(StateChangeReason.UNKNOWN);
+
         mReaderManager.onAddInfoBar(null, null, true);
-        assertEquals(0, mPanelManager.getRequestPanelShowCount());
+        assertEquals(1, mPanelManager.getRequestPanelShowCount());
         assertEquals(1, mPanelManager.getPanelHideCount());
 
         mReaderManager.onRemoveInfoBar(null, null, true);
-        assertEquals(1, mPanelManager.getRequestPanelShowCount());
+        assertEquals(2, mPanelManager.getRequestPanelShowCount());
         assertEquals(1, mPanelManager.getPanelHideCount());
     }
 
@@ -177,12 +181,14 @@
     @SmallTest
     @Feature({"ReaderModeManager"})
     public void testFullscreenEvents() {
+        mPanel.requestPanelShow(StateChangeReason.UNKNOWN);
+
         mReaderManager.onToggleFullscreenMode(null, true);
-        assertEquals(0, mPanelManager.getRequestPanelShowCount());
+        assertEquals(1, mPanelManager.getRequestPanelShowCount());
         assertEquals(1, mPanelManager.getPanelHideCount());
 
         mReaderManager.onToggleFullscreenMode(null, false);
-        assertEquals(1, mPanelManager.getRequestPanelShowCount());
+        assertEquals(2, mPanelManager.getRequestPanelShowCount());
         assertEquals(1, mPanelManager.getPanelHideCount());
     }
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadManagerServiceTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadManagerServiceTest.java
index ed5260d..8f1d438 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadManagerServiceTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadManagerServiceTest.java
@@ -68,18 +68,17 @@
         }
 
         public void waitTillExpectedCallsComplete() {
-            boolean result = false;
             try {
-                result = CriteriaHelper.pollForCriteria(new Criteria() {
-                    @Override
-                    public boolean isSatisfied() {
-                        return mExpectedCalls.isEmpty();
-                    }
-                });
+                CriteriaHelper.pollForCriteria(
+                        new Criteria("Failed while waiting for all calls to complete.") {
+                            @Override
+                            public boolean isSatisfied() {
+                                return mExpectedCalls.isEmpty();
+                            }
+                        });
             } catch (InterruptedException e) {
                 fail("Failed while waiting for all calls to complete." + e);
             }
-            assertTrue("Failed while waiting for all calls to complete.", result);
         }
 
         public MockDownloadNotifier andThen(MethodID method, Object param) {
@@ -135,18 +134,17 @@
         }
 
         public void waitForSnackbarControllerToFinish(final boolean success) {
-            boolean result = false;
             try {
-                result = CriteriaHelper.pollForCriteria(new Criteria() {
-                    @Override
-                    public boolean isSatisfied() {
-                        return success ? mSucceeded : mFailed;
-                    }
-                });
+                CriteriaHelper.pollForCriteria(
+                        new Criteria("Failed while waiting for all calls to complete.") {
+                            @Override
+                            public boolean isSatisfied() {
+                                return success ? mSucceeded : mFailed;
+                            }
+                        });
             } catch (InterruptedException e) {
                 fail("Failed while waiting for all calls to complete." + e);
             }
-            assertTrue("Failed while waiting for all calls to complete.", result);
         }
 
         @Override
@@ -451,13 +449,12 @@
         dService.setOMADownloadHandler(handler);
         dService.addOMADownloadToSharedPrefs(String.valueOf(downloadId) + "," + INSTALL_NOTIFY_URI);
         dService.clearPendingDownloadNotifications();
-        boolean result = CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return handler.mSuccess;
             }
         });
-        assertTrue(result);
         assertEquals(handler.mNofityURI, "http://test/test");
         manager.remove(downloadId);
     }
@@ -483,13 +480,12 @@
         dService.setOMADownloadHandler(handler);
         handler.setDownloadId(0);
         dService.enqueueDownloadManagerRequest(info, true);
-        boolean result = CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return handler.mDownloadId != 0;
             }
         });
-        assertTrue(result);
         handler.mDownloadId = handler.mDownloadInfo.getDownloadId();
         Set<String> downloads = dService.getStoredDownloadInfo(
                 DownloadManagerService.PENDING_OMA_DOWNLOADS);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadTest.java
index cd7777a..3edf0bc 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadTest.java
@@ -262,13 +262,13 @@
             }
         });
 
-        assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return getActivity().getActivityTab() == model.getTabAt(count - 1)
                         && getActivity().getActivityTab().isReady();
             }
-        }));
+        });
     }
 
     private void waitForNewTabToStabilize(final int numTabsAfterNewTab)
@@ -276,17 +276,18 @@
         // Wait until we have a new tab first. This should be called before checking the active
         // layout because the active layout changes StaticLayout --> SimpleAnimationLayout
         // --> (tab added) --> StaticLayout.
-        assertTrue("Actual tab count: " + getActivity().getCurrentTabModel().getCount(),
-                CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
-                    @Override
-                    public boolean isSatisfied() {
-                        return getActivity().getCurrentTabModel().getCount() >= numTabsAfterNewTab;
-                    }
-                }));
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+            @Override
+            public boolean isSatisfied() {
+                updateFailureReason(
+                        "Actual tab count: " + getActivity().getCurrentTabModel().getCount());
+                return getActivity().getCurrentTabModel().getCount() >= numTabsAfterNewTab;
+            }
+        });
 
         // Now wait until the new tab animation finishes. Something wonky happens
         // if we try to go to the new tab before this.
-        assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 CompositorViewHolder compositorViewHolder =
@@ -296,7 +297,7 @@
 
                 return layoutManager.getActiveLayout() instanceof StaticLayout;
             }
-        }));
+        });
     }
 
     /*
@@ -371,13 +372,13 @@
      */
     private void assertPollForInfoBarSize(final int size) throws InterruptedException {
         final InfoBarContainer container = getActivity().getActivityTab().getInfoBarContainer();
-        assertTrue("There should be " + size + " infobar but there are "
-                + getInfoBars().size() + " infobars.",
-                CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
-                    @Override
-                    public boolean isSatisfied() {
-                        return getInfoBars().size() == size && !container.isAnimating();
-                    }
-                }));
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+            @Override
+            public boolean isSatisfied() {
+                updateFailureReason("There should be " + size + " infobar but there are "
+                        + getInfoBars().size() + " infobars.");
+                return getInfoBars().size() == size && !container.isAnimating();
+            }
+        });
     }
 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadTestBase.java b/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadTestBase.java
index 6d516e2..674bb40 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadTestBase.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadTestBase.java
@@ -210,7 +210,7 @@
         cleanUpAllDownloads();
 
         try {
-            assertTrue(ApplicationUtils.waitForLibraryDependencies(getInstrumentation()));
+            ApplicationUtils.waitForLibraryDependencies(getInstrumentation());
         } catch (InterruptedException e) {
             fail("Library dependencies were never initialized.");
         }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/UrlOverridingTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/UrlOverridingTest.java
index 1d556b6..a3468595 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/UrlOverridingTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/UrlOverridingTest.java
@@ -184,7 +184,7 @@
         // For sub frames, the |loadFailCallback| run through different threads
         // from the ExternalNavigationHandler. As a result, there is no guarantee
         // when url override result would come.
-        assertTrue(CriteriaHelper.pollForUIThreadCriteria(
+        CriteriaHelper.pollForUIThreadCriteria(
                 new Criteria() {
                     @Override
                     public boolean isSatisfied() {
@@ -202,7 +202,7 @@
                         return expectedFinalUrl == null
                                 || TextUtils.equals(expectedFinalUrl, tab.getUrl());
                     }
-                }));
+                });
     }
 
     @SmallTest
@@ -296,12 +296,12 @@
         intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
         targetContext.startActivity(intent);
 
-        assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return mActivityMonitor.getHits() == 1;
             }
-        }));
+        });
     }
 
     @Override
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 e4f6de0..5e3a821 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
@@ -45,13 +45,12 @@
                     }
                 });
 
-        boolean gotResult = CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria("Should be finished by now.") {
             @Override
             public boolean isSatisfied() {
                 return task.isDone();
             }
         }, TIMEOUT_MS, RESULT_CHECK_INTERVAL_MS);
-        assertTrue("Should be finished by now.", gotResult);
         FeedbackData feedback = getResult(task);
         verifyConnections(feedback, ConnectivityCheckResult.NOT_CONNECTED);
         assertEquals("The timeout value is wrong.", TIMEOUT_MS, feedback.getTimeoutMs());
@@ -160,13 +159,17 @@
                                 null);
                     }
                 });
-        boolean gotResult = CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
-            @Override
-            public boolean isSatisfied() {
-                return task.isDone();
-            }
-        }, TIMEOUT_MS / 5, RESULT_CHECK_INTERVAL_MS);
-        assertFalse("Should not be finished by now.", gotResult);
+        try {
+            CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+                @Override
+                public boolean isSatisfied() {
+                    return task.isDone();
+                }
+            }, TIMEOUT_MS / 5, RESULT_CHECK_INTERVAL_MS);
+            fail("Should not be finished by now.");
+        } catch (AssertionError e) {
+            // TODO(tedchoc): This is horrible and should never timeout to determine success.
+        }
         FeedbackData feedback = getResult(task);
         verifyConnections(feedback, ConnectivityCheckResult.UNKNOWN);
         assertEquals("The timeout value is wrong.", TIMEOUT_MS, feedback.getTimeoutMs());
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/fullscreen/FullscreenManagerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/fullscreen/FullscreenManagerTest.java
index ed33716..51a599c 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/fullscreen/FullscreenManagerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/fullscreen/FullscreenManagerTest.java
@@ -83,16 +83,16 @@
         Tab tab = getActivity().getActivityTab();
         final TabWebContentsDelegateAndroid delegate = tab.getTabWebContentsDelegateAndroid();
 
-        assertTrue(waitForFullscreenFlag(tab, false));
-        assertTrue(waitForPersistentFullscreen(delegate, false));
+        waitForFullscreenFlag(tab, false);
+        waitForPersistentFullscreen(delegate, false);
 
         togglePersistentFullscreen(delegate, true);
-        assertTrue(waitForFullscreenFlag(tab, true));
-        assertTrue(waitForPersistentFullscreen(delegate, true));
+        waitForFullscreenFlag(tab, true);
+        waitForPersistentFullscreen(delegate, true);
 
         togglePersistentFullscreen(delegate, false);
-        assertTrue(waitForFullscreenFlag(tab, false));
-        assertTrue(waitForPersistentFullscreen(delegate, false));
+        waitForFullscreenFlag(tab, false);
+        waitForPersistentFullscreen(delegate, false);
     }
 
     @LargeTest
@@ -106,12 +106,12 @@
         final Tab tab = getActivity().getActivityTab();
         final TabWebContentsDelegateAndroid delegate = tab.getTabWebContentsDelegateAndroid();
 
-        assertTrue(waitForFullscreenFlag(tab, false));
-        assertTrue(waitForPersistentFullscreen(delegate, false));
+        waitForFullscreenFlag(tab, false);
+        waitForPersistentFullscreen(delegate, false);
 
         togglePersistentFullscreen(delegate, true);
-        assertTrue(waitForFullscreenFlag(tab, true));
-        assertTrue(waitForPersistentFullscreen(delegate, true));
+        waitForFullscreenFlag(tab, true);
+        waitForPersistentFullscreen(delegate, true);
 
         // There is a race condition in android when setting various system UI flags.
         // Adding this wait to allow the animation transitions to complete before continuing
@@ -126,8 +126,8 @@
                         view.getSystemUiVisibility() & ~View.SYSTEM_UI_FLAG_FULLSCREEN);
             }
         });
-        assertTrue(waitForFullscreenFlag(tab, true));
-        assertTrue(waitForPersistentFullscreen(delegate, true));
+        waitForFullscreenFlag(tab, true);
+        waitForPersistentFullscreen(delegate, true);
     }
 
     @LargeTest
@@ -206,14 +206,13 @@
         // When the top-controls are removed, we need a layout to trigger the
         // transparent region for the app to be updated.
         scrollTopControls(false);
-        boolean layoutOccured = CriteriaHelper.pollForUIThreadCriteria(
+        CriteriaHelper.pollForUIThreadCriteria(
                 new Criteria() {
                     @Override
                     public boolean isSatisfied() {
                         return layoutCount.get() > 0;
                     }
                 });
-        assertTrue(layoutOccured);
 
         getInstrumentation().runOnMainSync(new Runnable() {
             @Override
@@ -268,7 +267,7 @@
 
         ChromeFullscreenManager fullscreenManager = getActivity().getFullscreenManager();
         fullscreenManager.setAnimationDurationsForTest(1, 1);
-        assertTrue(waitForNoBrowserTopControlsOffset());
+        waitForNoBrowserTopControlsOffset();
         assertEquals(fullscreenManager.getControlOffset(), 0f);
 
         scrollTopControls(false);
@@ -290,7 +289,7 @@
                 delegate.rendererResponsive();
             }
         });
-        assertTrue(waitForNoBrowserTopControlsOffset());
+        waitForNoBrowserTopControlsOffset();
     }
 
     /*
@@ -349,7 +348,7 @@
         dragStart(dragX, dragStartY, downTime);
         dragTo(dragX, dragX, dragStartY, dragEndY, 100, downTime);
         dragEnd(dragX, dragEndY, downTime);
-        assertTrue(waitForNoBrowserTopControlsOffset());
+        waitForNoBrowserTopControlsOffset();
         assertEquals(fullscreenManager.getControlOffset(), 0f);
 
         Tab tab = getActivity().getActivityTab();
@@ -416,9 +415,9 @@
         }
     }
 
-    private boolean waitForFullscreenFlag(final Tab tab, final boolean state)
+    private void waitForFullscreenFlag(final Tab tab, final boolean state)
             throws InterruptedException {
-        return CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return isFullscreenFlagSet(tab, state);
@@ -426,9 +425,9 @@
         });
     }
 
-    private boolean waitForPersistentFullscreen(final TabWebContentsDelegateAndroid delegate,
+    private void waitForPersistentFullscreen(final TabWebContentsDelegateAndroid delegate,
             final boolean state) throws InterruptedException {
-        return CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return state == delegate.isFullscreenForTabOrPending();
@@ -453,9 +452,9 @@
         });
     }
 
-    private boolean waitForNoBrowserTopControlsOffset() throws InterruptedException {
+    private void waitForNoBrowserTopControlsOffset() throws InterruptedException {
         final ChromeFullscreenManager fullscreenManager = getActivity().getFullscreenManager();
-        return CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return !fullscreenManager.hasBrowserControlOffsetOverride();
@@ -463,8 +462,8 @@
         });
     }
 
-    private boolean waitForPageToBeScrollable(final Tab tab) throws InterruptedException {
-        return CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+    private void waitForPageToBeScrollable(final Tab tab) throws InterruptedException {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 ContentViewCore contentViewCore = tab.getContentViewCore();
@@ -474,8 +473,8 @@
         });
     }
 
-    private boolean waitForEditableNodeToLoseFocus(final Tab tab) throws InterruptedException {
-        return CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+    private void waitForEditableNodeToLoseFocus(final Tab tab) throws InterruptedException {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 ContentViewCore contentViewCore = tab.getContentViewCore();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/infobar/InfoBarTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/infobar/InfoBarTest.java
index 1fe81c88..86fc188 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/infobar/InfoBarTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/infobar/InfoBarTest.java
@@ -57,14 +57,14 @@
         super.setUp();
 
         // Register for animation notifications
-        assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
+        CriteriaHelper.pollForCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 if (getActivity().getActivityTab() == null) return false;
                 if (getActivity().getActivityTab().getInfoBarContainer() == null) return false;
                 return true;
             }
-        }));
+        });
         InfoBarContainer container = getActivity().getActivityTab().getInfoBarContainer();
         mListener =  new InfoBarTestAnimationListener();
         container.setAnimationListener(mListener);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/infobar/InfoBarTest2.java b/chrome/android/javatests/src/org/chromium/chrome/browser/infobar/InfoBarTest2.java
index a73cd0fd..8e3a55c 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/infobar/InfoBarTest2.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/infobar/InfoBarTest2.java
@@ -175,7 +175,7 @@
                         networkPredictionOptions);
             }
         };
-    };
+    }
 
     /**
      * Same as testInfoBarExpiration but with prerender turned-off.
@@ -375,14 +375,13 @@
         addInfoBarToCurrentTab(infoBar);
 
         // A layout must occur to recalculate the transparent region.
-        boolean layoutOccured = CriteriaHelper.pollForUIThreadCriteria(
+        CriteriaHelper.pollForUIThreadCriteria(
                 new Criteria() {
                     @Override
                     public boolean isSatisfied() {
                         return layoutCount.get() > 0;
                     }
                 });
-        assertTrue(layoutOccured);
 
         final Rect fullDisplayFrame = new Rect();
         final Rect fullDisplayFrameMinusContainer = new Rect();
@@ -414,14 +413,13 @@
         dismissInfoBar(infoBar);
 
         // A layout must occur to recalculate the transparent region.
-        layoutOccured = CriteriaHelper.pollForUIThreadCriteria(
+        CriteriaHelper.pollForUIThreadCriteria(
                 new Criteria() {
                     @Override
                     public boolean isSatisfied() {
                         return layoutCount.get() > 0;
                     }
                 });
-        assertTrue(layoutOccured);
 
         getInstrumentation().runOnMainSync(new Runnable() {
             @Override
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/infobar/PermissionUpdateInfobarTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/infobar/PermissionUpdateInfobarTest.java
index 5fb164a..dbc5484d 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/infobar/PermissionUpdateInfobarTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/infobar/PermissionUpdateInfobarTest.java
@@ -56,14 +56,14 @@
         ChromeTabUtils.newTabFromMenu(getInstrumentation(), getActivity());
 
         // Register for animation notifications
-        assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
+        CriteriaHelper.pollForCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 if (getActivity().getActivityTab() == null) return false;
                 if (getActivity().getActivityTab().getInfoBarContainer() == null) return false;
                 return true;
             }
-        }));
+        });
         InfoBarContainer container = getActivity().getActivityTab().getInfoBarContainer();
         mListener =  new InfoBarTestAnimationListener();
         container.setAnimationListener(mListener);
@@ -114,19 +114,19 @@
             assertFalse(webContents.isDestroyed());
 
             ChromeTabUtils.closeCurrentTab(getInstrumentation(), getActivity());
-            assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+            CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
                 @Override
                 public boolean isSatisfied() {
                     return webContents.isDestroyed();
                 }
-            }));
+            });
 
-            assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+            CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
                 @Override
                 public boolean isSatisfied() {
                     return getActivity().getTabModelSelector().getModel(false).getCount() == 1;
                 }
-            }));
+            });
         } finally {
             ThreadUtils.runOnUiThreadBlocking(new Runnable() {
                 @Override
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/input/SelectPopupOtherContentViewTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/input/SelectPopupOtherContentViewTest.java
index 5bda355d..84682c8f 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/input/SelectPopupOtherContentViewTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/input/SelectPopupOtherContentViewTest.java
@@ -37,7 +37,11 @@
             + "</select>"
             + "</body></html>");
 
-    private class PopupShowingCriteria implements Criteria {
+    private class PopupShowingCriteria extends Criteria {
+        public PopupShowingCriteria() {
+            super("The select popup did not show up on click.");
+        }
+
         @Override
         public boolean isSatisfied() {
             ContentViewCore contentViewCore = getActivity().getCurrentContentViewCore();
@@ -72,8 +76,7 @@
 
         // Once clicked, the popup should show up.
         DOMUtils.clickNode(this, viewCore, "select");
-        assertTrue("The select popup did not show up on click.",
-                CriteriaHelper.pollForCriteria(new PopupShowingCriteria()));
+        CriteriaHelper.pollForCriteria(new PopupShowingCriteria());
 
         // Now create and destroy a different ContentView.
         ThreadUtils.runOnUiThreadBlocking(new Runnable() {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/invalidation/ChromeBrowserSyncAdapterTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/invalidation/ChromeBrowserSyncAdapterTest.java
index d707bdd..932cb9f 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/invalidation/ChromeBrowserSyncAdapterTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/invalidation/ChromeBrowserSyncAdapterTest.java
@@ -45,13 +45,13 @@
         intent.addCategory(Intent.CATEGORY_HOME);
         context.startActivity(intent);
 
-        assertTrue("Activity should have been sent to background",
-                CriteriaHelper.pollForCriteria(new Criteria() {
-                    @Override
-                    public boolean isSatisfied() {
-                        return !ApplicationStatus.hasVisibleActivities();
-                    }
-                }, WAIT_FOR_LAUNCHER_MS, POLL_INTERVAL_MS));
+        CriteriaHelper.pollForCriteria(new Criteria(
+                "Activity should have been sent to background") {
+            @Override
+            public boolean isSatisfied() {
+                return !ApplicationStatus.hasVisibleActivities();
+            }
+        }, WAIT_FOR_LAUNCHER_MS, POLL_INTERVAL_MS);
     }
 
     private void performSyncWithBundle(Bundle bundle) {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/invalidation/ChromiumSyncAdapterTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/invalidation/ChromiumSyncAdapterTest.java
index 35e5d719..da63fb0 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/invalidation/ChromiumSyncAdapterTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/invalidation/ChromiumSyncAdapterTest.java
@@ -95,13 +95,12 @@
         intent.addCategory(Intent.CATEGORY_HOME);
         activity.startActivity(intent);
 
-        assertTrue(
-                "Activity should have been resumed", CriteriaHelper.pollForCriteria(new Criteria() {
-                    @Override
-                    public boolean isSatisfied() {
-                        return !isActivityResumed();
-                    }
-                }, WAIT_FOR_LAUNCHER_MS, POLL_INTERVAL_MS));
+        CriteriaHelper.pollForCriteria(new Criteria("Activity should have been resumed") {
+            @Override
+            public boolean isSatisfied() {
+                return !isActivityResumed();
+            }
+        }, WAIT_FOR_LAUNCHER_MS, POLL_INTERVAL_MS);
     }
 
     private boolean isActivityResumed() {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/media/ui/PauseOnHeadsetUnplugTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/media/ui/PauseOnHeadsetUnplugTest.java
index 5a1c982..944174b 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/media/ui/PauseOnHeadsetUnplugTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/media/ui/PauseOnHeadsetUnplugTest.java
@@ -41,11 +41,11 @@
 
         assertTrue(DOMUtils.isMediaPaused(tab.getWebContents(), VIDEO_ID));
         DOMUtils.playMedia(tab.getWebContents(), VIDEO_ID);
-        assertTrue(DOMUtils.waitForMediaPlay(tab.getWebContents(), VIDEO_ID));
-        assertTrue(waitForNotificationReady());
+        DOMUtils.waitForMediaPlay(tab.getWebContents(), VIDEO_ID);
+        waitForNotificationReady();
 
         simulateHeadsetUnplug();
-        assertTrue(DOMUtils.waitForMediaPause(tab.getWebContents(), VIDEO_ID));
+        DOMUtils.waitForMediaPause(tab.getWebContents(), VIDEO_ID);
     }
 
     @Override
@@ -53,15 +53,14 @@
         startMainActivityWithURL(TestHttpServerClient.getUrl(TEST_URL));
     }
 
-    private boolean waitForNotificationReady()
-            throws InterruptedException {
-        return CriteriaHelper.pollForCriteria(new Criteria() {
-                @Override
-                public boolean isSatisfied() {
-                    return MediaNotificationManager.hasManagerForTesting(
-                            R.id.media_playback_notification);
-                }
-            });
+    private void waitForNotificationReady() throws InterruptedException {
+        CriteriaHelper.pollForCriteria(new Criteria() {
+            @Override
+            public boolean isSatisfied() {
+                return MediaNotificationManager.hasManagerForTesting(
+                        R.id.media_playback_notification);
+            }
+        });
     }
 
     private void simulateHeadsetUnplug() {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/notifications/NotificationTestBase.java b/chrome/android/javatests/src/org/chromium/chrome/browser/notifications/NotificationTestBase.java
index d812ff2..0105338 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/notifications/NotificationTestBase.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/notifications/NotificationTestBase.java
@@ -95,7 +95,7 @@
      * @return The NotificationEntry object tracked by the MockNotificationManagerProxy.
      */
     protected NotificationEntry waitForNotification() throws Exception {
-        assertTrue(waitForNotificationManagerMutation());
+        waitForNotificationManagerMutation();
         List<NotificationEntry> notifications = getNotificationEntries();
         assertEquals(1, notifications.size());
         return notifications.get(0);
@@ -108,11 +108,9 @@
     /**
      * Waits for a mutation to occur in the mocked notification manager. This indicates that Chrome
      * called into Android to notify or cancel a notification.
-     *
-     * @return Whether the wait was successful.
      */
-    protected boolean waitForNotificationManagerMutation() throws Exception {
-        return CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+    protected void waitForNotificationManagerMutation() throws Exception {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return mMockNotificationManager.getMutationCountAndDecrement() > 0;
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/notifications/NotificationUIManagerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/notifications/NotificationUIManagerTest.java
index 397d1dc..d134f2d 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/notifications/NotificationUIManagerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/notifications/NotificationUIManagerTest.java
@@ -212,7 +212,7 @@
 
         // The Service Worker will close the notification upon receiving the notificationclick
         // event. This will eventually bubble up to a call to cancel() in the NotificationManager.
-        assertTrue(waitForNotificationManagerMutation());
+        waitForNotificationManagerMutation();
         assertTrue(getNotificationEntries().isEmpty());
     }
 
@@ -228,13 +228,13 @@
         setNotificationContentSettingForCurrentOrigin(ContentSetting.ALLOW);
 
         runJavaScriptCodeInCurrentTab("showNotification('MyNotification', {tag: 'myTag'});");
-        assertTrue(waitForNotificationManagerMutation());
+        waitForNotificationManagerMutation();
         List<NotificationEntry> notifications = getNotificationEntries();
         String tag = notifications.get(0).tag;
         int id = notifications.get(0).id;
 
         runJavaScriptCodeInCurrentTab("showNotification('SecondNotification', {tag: 'myTag'});");
-        assertTrue(waitForNotificationManagerMutation());
+        waitForNotificationManagerMutation();
 
         // Verify that the notification was successfully replaced.
         notifications = getNotificationEntries();
@@ -262,7 +262,7 @@
 
         // Open the first notification and verify it is displayed.
         runJavaScriptCodeInCurrentTab("showNotification('One');");
-        assertTrue(waitForNotificationManagerMutation());
+        waitForNotificationManagerMutation();
         List<NotificationEntry> notifications = getNotificationEntries();
         assertEquals(1, notifications.size());
         Notification notificationOne = notifications.get(0).notification;
@@ -270,7 +270,7 @@
 
         // Open the second notification and verify it is displayed.
         runJavaScriptCodeInCurrentTab("showNotification('Two');");
-        assertTrue(waitForNotificationManagerMutation());
+        waitForNotificationManagerMutation();
         notifications = getNotificationEntries();
         assertEquals(2, notifications.size());
         Notification notificationTwo = notifications.get(1).notification;
@@ -294,7 +294,7 @@
         // notificationclick event is fired. The test service worker will close the notification
         // upon receiving the event.
         notificationOne.contentIntent.send();
-        assertTrue(waitForNotificationManagerMutation());
+        waitForNotificationManagerMutation();
         notifications = getNotificationEntries();
         assertEquals(1, notifications.size());
         assertEquals("Two",
@@ -302,7 +302,7 @@
 
         // Close the last notification and verify that none remain.
         notifications.get(0).notification.contentIntent.send();
-        assertTrue(waitForNotificationManagerMutation());
+        waitForNotificationManagerMutation();
         assertTrue(getNotificationEntries().isEmpty());
     }
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/DocumentModeRecentlyClosedTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/DocumentModeRecentlyClosedTest.java
index 5741dbb6..e7111cd7 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/DocumentModeRecentlyClosedTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/DocumentModeRecentlyClosedTest.java
@@ -106,21 +106,21 @@
         // DocumentTabModel update.
         activityDelegate.mExtraRegularTask = null;
         ApplicationTestUtils.launchChrome(mContext);
-        assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
+        CriteriaHelper.pollForCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 Activity lastActivity = ApplicationStatus.getLastTrackedFocusedActivity();
                 return lastActivity instanceof DocumentActivity;
             }
-        }));
+        });
 
         // Wait until the DocumentTabModel updates and shows a single tab.
-        assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
+        CriteriaHelper.pollForCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return selector.getTotalTabCount() == 1;
             }
-        }));
+        });
 
         // Check recently closed, make sure it shows one open and one closed tab.
         DocumentActivity activity =
@@ -165,12 +165,12 @@
                     selector.getModel(false).closeTabAt(0);
                 }
         });
-        assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
                 @Override
                 public boolean isSatisfied() {
                     return selector.getTotalTabCount() == 2;
                 }
-        }));
+        });
 
         // Check that the right things appear in Recent Tabs.
         List<CurrentlyOpenTab> afterOpenTabs = recentTabsManager.getCurrentlyOpenTabs();
@@ -239,12 +239,12 @@
         ActivityDelegate delegate =
                 new ActivityDelegateImpl(DocumentActivity.class, IncognitoDocumentActivity.class);
         delegate.finishAndRemoveTask(false, tabIds[0]);
-        assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
+        CriteriaHelper.pollForCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return selector.getTotalTabCount() == 2;
             }
-        }));
+        });
 
         // Check that the Tab shows up under Recently closed.
         final DocumentRecentTabsManager recentTabsManager = getRecentTabsManager(thirdActivity);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/FakeMostVisitedSites.java b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/FakeMostVisitedSites.java
index d97a21e..3b2da986d 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/FakeMostVisitedSites.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/FakeMostVisitedSites.java
@@ -67,7 +67,7 @@
     }
 
     @Override
-    public void recordTileTypeMetrics(int[] tileTypes, boolean isIconMode) {
+    public void recordTileTypeMetrics(int[] tileTypes) {
         // Metrics are stubbed out.
     }
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/NewTabPageTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/NewTabPageTest.java
index 248f646e..abce9bdf4 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/NewTabPageTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/NewTabPageTest.java
@@ -98,13 +98,13 @@
         singleClickView(mFakebox);
         waitForFakeboxFocusAnimationComplete(mNtp);
         UrlBar urlBar = (UrlBar) getActivity().findViewById(R.id.url_bar);
-        assertTrue(OmniboxTestUtils.waitForFocusAndKeyboardActive(urlBar, true));
+        OmniboxTestUtils.waitForFocusAndKeyboardActive(urlBar, true);
         int afterFocusFakeboxTop = getFakeboxTop(mNtp);
         assertTrue(afterFocusFakeboxTop < initialFakeboxTop);
 
         OmniboxTestUtils.toggleUrlBarFocus(urlBar, false);
         waitForFakeboxTopPosition(mNtp, initialFakeboxTop);
-        assertTrue(OmniboxTestUtils.waitForFocusAndKeyboardActive(urlBar, false));
+        OmniboxTestUtils.waitForFocusAndKeyboardActive(urlBar, false);
     }
 
     /**
@@ -117,7 +117,7 @@
         singleClickView(mFakebox);
         waitForFakeboxFocusAnimationComplete(mNtp);
         final UrlBar urlBar = (UrlBar) getActivity().findViewById(R.id.url_bar);
-        assertTrue(OmniboxTestUtils.waitForFocusAndKeyboardActive(urlBar, true));
+        OmniboxTestUtils.waitForFocusAndKeyboardActive(urlBar, true);
 
         getInstrumentation().sendStringSync(TEST_PAGE);
         LocationBarLayout locationBar =
@@ -253,8 +253,8 @@
             final View v = urlBar;
             KeyUtils.singleKeyEventView(getInstrumentation(), v, KeyEvent.KEYCODE_ENTER);
 
-            assertTrue(waitForUrlFocusAnimationsDisabledState(true));
-            assertTrue(waitForTabLoading());
+            waitForUrlFocusAnimationsDisabledState(true);
+            waitForTabLoading();
 
             ThreadUtils.runOnUiThreadBlocking(new Runnable() {
                 @Override
@@ -262,7 +262,7 @@
                     mTab.stopLoading();
                 }
             });
-            assertTrue(waitForUrlFocusAnimationsDisabledState(false));
+            waitForUrlFocusAnimationsDisabledState(false);
             delaySemaphore.release();
             loadedCallback.waitForCallback(0);
             assertFalse(getUrlFocusAnimatonsDisabled());
@@ -280,9 +280,9 @@
         });
     }
 
-    private boolean waitForUrlFocusAnimationsDisabledState(final boolean disabled)
+    private void waitForUrlFocusAnimationsDisabledState(final boolean disabled)
             throws InterruptedException {
-        return CriteriaHelper.pollForCriteria(new Criteria() {
+        CriteriaHelper.pollForCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return getUrlFocusAnimatonsDisabled() == disabled;
@@ -290,8 +290,8 @@
         });
     }
 
-    private boolean waitForTabLoading() throws InterruptedException {
-        return CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+    private void waitForTabLoading() throws InterruptedException {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return mTab.isLoading();
@@ -303,19 +303,14 @@
         waitForUrlFocusPercent(ntp, 1f);
     }
 
-    private void waitForFakeboxUnfocusAnimationComplete(NewTabPage ntp)
-            throws InterruptedException {
-        waitForUrlFocusPercent(ntp, 0f);
-    }
-
     private void waitForUrlFocusPercent(final NewTabPage ntp, final float percent)
             throws InterruptedException {
-        assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return ntp.getNewTabPageView().getUrlFocusChangeAnimationPercent() == percent;
             }
-        }));
+        });
     }
 
     private void clickFakebox() {
@@ -343,11 +338,11 @@
      */
     private void waitForFakeboxTopPosition(final NewTabPage ntp, final int position)
             throws InterruptedException {
-        assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return getFakeboxTop(ntp) == position;
             }
-        }));
+        });
     }
 }
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 f3580fd..357a47d 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
@@ -183,14 +183,14 @@
                 mOfflinePageBridge.markPageAccessed(bookmarkId);
             }
         });
-        assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 OfflinePageItem offlinePage =
                         mOfflinePageBridge.getPageByBookmarkId(bookmarkId);
                 return offlinePage.getAccessCount() == expectedAccessCount;
             }
-        }));
+        });
     }
 
     private void deletePage(BookmarkId bookmarkId, final int expectedResult)
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/omaha/OmahaUpdateInfoBarTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/omaha/OmahaUpdateInfoBarTest.java
index 95e3385..8cf0327 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/omaha/OmahaUpdateInfoBarTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/omaha/OmahaUpdateInfoBarTest.java
@@ -127,12 +127,12 @@
         startMainActivityWithURL(url);
 
         // Check to make sure that the version numbers get queried.
-        assertTrue("Main didn't ask Omaha for version numbers.", versionNumbersQueried());
+        waitForVersionNumbersQueried();
     }
 
-    private boolean versionNumbersQueried() throws Exception {
-        return CriteriaHelper.pollForCriteria(
-                new Criteria() {
+    private void waitForVersionNumbersQueried() throws Exception {
+        CriteriaHelper.pollForCriteria(
+                new Criteria("Main didn't ask Omaha for version numbers.") {
                     @Override
                     public boolean isSatisfied() {
                         return mMockVersionNumberGetter.askedForCurrentVersion()
@@ -169,8 +169,8 @@
     /**
      * Waits until the NavigateToURLInfoBar appears for the current tab.
      */
-    private boolean correctInfoBarAdded() throws Exception {
-        return CriteriaHelper.pollForCriteria(
+    private void correctInfoBarAdded() throws Exception {
+        CriteriaHelper.pollForCriteria(
                 new Criteria() {
                     @Override
                     public boolean isSatisfied() {
@@ -184,8 +184,8 @@
     /**
      * Waits until the NavigateToURLInfoBar goes away.
      */
-    private boolean correctInfoBarRemoved() throws Exception {
-        return CriteriaHelper.pollForCriteria(
+    private void correctInfoBarRemoved() throws Exception {
+        CriteriaHelper.pollForCriteria(
                 new Criteria() {
                     @Override
                     public boolean isSatisfied() {
@@ -205,23 +205,32 @@
 
         if (url == null) {
             // The InfoBar shouldn't be created yet because we're on the NTP.
-            assertFalse("InfoBar shown on NTP.", correctInfoBarAdded());
+            try {
+                correctInfoBarAdded();
+                fail("Infobar should not have been added");
+            } catch (AssertionError e) {
+                // TODO(tedchoc): This is horrible and should never timeout to determine success.
+            }
 
             // Navigate somewhere else and then check for the InfoBar.
             loadUrl(UrlUtils.getIsolatedTestFileUrl(HTML_FILENAME_1));
-            assertTrue("InfoBar failed to show after navigating from NTP.",
-                    correctInfoBarAdded());
+            correctInfoBarAdded();
         } else {
             // The InfoBar be shown ASAP since we're not on the NTP.
-            assertTrue("InfoBar failed to show.", correctInfoBarAdded());
+            correctInfoBarAdded();
         }
 
         // Make sure the InfoBar doesn't disappear immediately.
-        assertFalse("InfoBar was removed too quickly.", correctInfoBarRemoved());
+        try {
+            correctInfoBarRemoved();
+            fail("InfoBar was removed too quickly.");
+        } catch (AssertionError e) {
+            // TODO(tedchoc): This is horrible and should never timeout to determine success.
+        }
 
         // Make sure the InfoBar goes away once we navigate somewhere else on the same tab.
         loadUrl(UrlUtils.getIsolatedTestFileUrl(HTML_FILENAME_2));
-        assertTrue("InfoBar is still showing", correctInfoBarRemoved());
+        correctInfoBarRemoved();
     }
 
     /**
@@ -231,9 +240,19 @@
     private void checkInfobarDoesNotAppear(String currentVersion, String latestVersion, String url)
             throws Exception {
         prepareAndStartMainActivity(currentVersion, latestVersion, url);
-        assertFalse("Infobar is showing.", correctInfoBarAdded());
+        try {
+            correctInfoBarAdded();
+            fail("Infobar is showing.");
+        } catch (AssertionError e) {
+            // TODO(tedchoc): This is horrible and should never timeout to determine success.
+        }
         loadUrl(UrlUtils.getIsolatedTestFileUrl(HTML_FILENAME_2));
-        assertFalse("Infobar is now showing", correctInfoBarAdded());
+        try {
+            correctInfoBarAdded();
+            fail("Infobar is now showing");
+        } catch (AssertionError e) {
+            // TODO(tedchoc): This is horrible and should never timeout to determine success.
+        }
     }
 
     @MediumTest
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/OmniboxTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/OmniboxTest.java
index be88d60..222c248c 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/OmniboxTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/OmniboxTest.java
@@ -102,24 +102,22 @@
         final UrlBar urlBar = (UrlBar) getActivity().findViewById(R.id.url_bar);
 
         OmniboxTestUtils.toggleUrlBarFocus(urlBar, true);
-        assertTrue("Soft input mode failed to switch on focus",
-                CriteriaHelper.pollForCriteria(new Criteria() {
-                    @Override
-                    public boolean isSatisfied() {
-                        return getActivity().getWindow().getAttributes().softInputMode
-                                == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN;
-                    }
-                }));
+        CriteriaHelper.pollForCriteria(new Criteria("Soft input mode failed to switch on focus") {
+            @Override
+            public boolean isSatisfied() {
+                return getActivity().getWindow().getAttributes().softInputMode
+                        == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN;
+            }
+        });
 
         OmniboxTestUtils.toggleUrlBarFocus(urlBar, false);
-        assertTrue("Soft input mode failed to switch on unfocus",
-                CriteriaHelper.pollForCriteria(new Criteria() {
-                    @Override
-                    public boolean isSatisfied() {
-                        return getActivity().getWindow().getAttributes().softInputMode
-                                == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
-                    }
-                }));
+        CriteriaHelper.pollForCriteria(new Criteria("Soft input mode failed to switch on unfocus") {
+            @Override
+            public boolean isSatisfied() {
+                return getActivity().getWindow().getAttributes().softInputMode
+                        == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
+            }
+        });
     }
 
     /**
@@ -146,13 +144,13 @@
 
         OmniboxTestUtils.toggleUrlBarFocus(urlBar, true);
 
-        assertTrue("Should have requested zero suggest on focusing",
-                CriteriaHelper.pollForCriteria(new Criteria() {
-                    @Override
-                    public boolean isSatisfied() {
-                        return controller.numZeroSuggestRequests() == 1;
-                    }
-                }));
+        CriteriaHelper.pollForCriteria(new Criteria(
+                "Should have requested zero suggest on focusing") {
+            @Override
+            public boolean isSatisfied() {
+                return controller.numZeroSuggestRequests() == 1;
+            }
+        });
     }
 
     /**
@@ -188,13 +186,12 @@
             }
         });
 
-        assertTrue("Should have drawn the delete button",
-                CriteriaHelper.pollForCriteria(new Criteria() {
-                    @Override
-                    public boolean isSatisfied() {
-                        return deleteButton.getWidth() > 0;
-                    }
-                }));
+        CriteriaHelper.pollForCriteria(new Criteria("Should have drawn the delete button") {
+            @Override
+            public boolean isSatisfied() {
+                return deleteButton.getWidth() > 0;
+            }
+        });
 
         // The click view below ends up clicking on the menu button underneath the delete button
         // for some time after the delete button appears. Wait for UI to settle down before
@@ -203,13 +200,13 @@
 
         singleClickView(deleteButton);
 
-        assertTrue("Should have requested zero suggest results on url bar empty",
-                CriteriaHelper.pollForCriteria(new Criteria() {
-                    @Override
-                    public boolean isSatisfied() {
-                        return controller.numZeroSuggestRequests() == 1;
-                    }
-                }));
+        CriteriaHelper.pollForCriteria(new Criteria(
+                "Should have requested zero suggest results on url bar empty") {
+            @Override
+            public boolean isSatisfied() {
+                return controller.numZeroSuggestRequests() == 1;
+            }
+        });
     }
 
     @MediumTest
@@ -244,13 +241,13 @@
 
         assertEquals("No calls to zero suggest yet", 0, controller.numZeroSuggestRequests());
         KeyUtils.singleKeyEventView(getInstrumentation(), urlBar, KeyEvent.KEYCODE_DEL);
-        assertTrue("Should have requested zero suggest results on url bar empty",
-                CriteriaHelper.pollForCriteria(new Criteria() {
-                    @Override
-                    public boolean isSatisfied() {
-                        return controller.numZeroSuggestRequests() == 1;
-                    }
-                }));
+        CriteriaHelper.pollForCriteria(new Criteria(
+                "Should have requested zero suggest results on url bar empty") {
+            @Override
+            public boolean isSatisfied() {
+                return controller.numZeroSuggestRequests() == 1;
+            }
+        });
     }
 
     // Sanity check that no text is displayed in the omnibox when on the NTP page and that the hint
@@ -740,8 +737,7 @@
     private void verifyOmniboxSuggestionAlignment(
             final LocationBarLayout locationBar, final int expectedSuggestionCount,
             final int expectedLayoutDirection) throws InterruptedException {
-        assertTrue(OmniboxTestUtils.waitForOmniboxSuggestions(
-                locationBar, expectedSuggestionCount));
+        OmniboxTestUtils.waitForOmniboxSuggestions(locationBar, expectedSuggestionCount);
         ThreadUtils.runOnUiThreadBlocking(new Runnable() {
             @Override
             public void run() {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/UrlBarTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/UrlBarTest.java
index f4c5de5..fa733fc 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/UrlBarTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/UrlBarTest.java
@@ -544,7 +544,7 @@
         UrlBar urlBar = getUrlBar();
         assertNotNull(urlBar);
         OmniboxTestUtils.toggleUrlBarFocus(urlBar, true);
-        assertTrue(OmniboxTestUtils.waitForFocusAndKeyboardActive(urlBar, true));
+        OmniboxTestUtils.waitForFocusAndKeyboardActive(urlBar, true);
     }
 
     @SmallTest
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/partnercustomizations/PartnerDisableIncognitoModeIntegrationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/partnercustomizations/PartnerDisableIncognitoModeIntegrationTest.java
index ff00a9d..2e8fb3c 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/partnercustomizations/PartnerDisableIncognitoModeIntegrationTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/partnercustomizations/PartnerDisableIncognitoModeIntegrationTest.java
@@ -73,9 +73,9 @@
         }
     }
 
-    private boolean waitForParentalControlsEnabledState(final boolean parentalControlsEnabled)
+    private void waitForParentalControlsEnabledState(final boolean parentalControlsEnabled)
             throws InterruptedException {
-        return CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 // areParentalControlsEnabled is updated on a background thread, so we
@@ -122,7 +122,7 @@
     public void testIncognitoEnabledIfNoParentalControls() throws InterruptedException {
         setParentalControlsEnabled(false);
         startMainActivityOnBlankPage();
-        assertTrue(waitForParentalControlsEnabledState(false));
+        waitForParentalControlsEnabledState(false);
         newIncognitoTabFromMenu();
     }
 
@@ -132,12 +132,12 @@
             throws InterruptedException, ExecutionException {
         setParentalControlsEnabled(true);
         startMainActivityOnBlankPage();
-        assertTrue(waitForParentalControlsEnabledState(true));
+        waitForParentalControlsEnabledState(true);
         assertIncognitoMenuItemEnabled(false);
 
         setParentalControlsEnabled(false);
         toggleActivityForegroundState();
-        assertTrue(waitForParentalControlsEnabledState(false));
+        waitForParentalControlsEnabledState(false);
         assertIncognitoMenuItemEnabled(true);
     }
 
@@ -146,7 +146,7 @@
     public void testEnabledParentalControlsClosesIncognitoTabs() throws InterruptedException {
         setParentalControlsEnabled(false);
         startMainActivityOnBlankPage();
-        assertTrue(waitForParentalControlsEnabledState(false));
+        waitForParentalControlsEnabledState(false);
 
         loadUrlInNewTab(TEST_URLS[0], true);
         loadUrlInNewTab(TEST_URLS[1], true);
@@ -155,14 +155,13 @@
 
         setParentalControlsEnabled(true);
         toggleActivityForegroundState();
-        assertTrue(waitForParentalControlsEnabledState(true));
+        waitForParentalControlsEnabledState(true);
 
-        assertTrue("Incognito tabs did not close as expected",
-                CriteriaHelper.pollForCriteria(new Criteria() {
-                    @Override
-                    public boolean isSatisfied() {
-                        return incognitoTabsCount() == 0;
-                    }
-                }));
+        CriteriaHelper.pollForCriteria(new Criteria("Incognito tabs did not close as expected") {
+            @Override
+            public boolean isSatisfied() {
+                return incognitoTabsCount() == 0;
+            }
+        });
     }
 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/partnercustomizations/PartnerHomepageIntegrationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/partnercustomizations/PartnerHomepageIntegrationTest.java
index 4ea31a8..d0da38e 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/partnercustomizations/PartnerHomepageIntegrationTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/partnercustomizations/PartnerHomepageIntegrationTest.java
@@ -11,7 +11,6 @@
 import android.test.suitebuilder.annotation.MediumTest;
 import android.view.View;
 import android.widget.Button;
-import android.widget.Checkable;
 import android.widget.EditText;
 
 import org.chromium.base.ThreadUtils;
@@ -111,7 +110,7 @@
                 (SwitchCompat) homepagePreferenceActivity.findViewById(R.id.switch_widget);
         assertNotNull(homepageSwitch);
         TouchCommon.singleClickView(homepageSwitch);
-        waitForCheckedState(homepageSwitch, false);
+        waitForCheckedState(homepagePreferenceActivity, false);
         homepagePreferenceActivity.finish();
 
         // Assert no homepage button.
@@ -129,7 +128,7 @@
         homepageSwitch = (SwitchCompat) homepagePreferenceActivity.findViewById(R.id.switch_widget);
         assertNotNull(homepageSwitch);
         TouchCommon.singleClickView(homepageSwitch);
-        waitForCheckedState(homepageSwitch, true);
+        waitForCheckedState(homepagePreferenceActivity, true);
         homepagePreferenceActivity.finish();
 
         // Assert homepage button.
@@ -143,12 +142,16 @@
         });
     }
 
-    private boolean waitForCheckedState(final Checkable view, final boolean isChecked)
+    private void waitForCheckedState(final Preferences preferenceActivity, final boolean isChecked)
             throws InterruptedException {
-        return CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
-                return view.isChecked() == isChecked;
+                // The underlying switch view in the preference can change, so we need to fetch
+                // it each time to ensure we are checking the activity view.
+                SwitchCompat homepageSwitch =
+                        (SwitchCompat) preferenceActivity.findViewById(R.id.switch_widget);
+                return homepageSwitch.isChecked() == isChecked;
             }
         });
     }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/privacy/ClearBrowsingDataDialogFragmentTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/privacy/ClearBrowsingDataDialogFragmentTest.java
index 3ea1a98..0a85e4f 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/privacy/ClearBrowsingDataDialogFragmentTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/privacy/ClearBrowsingDataDialogFragmentTest.java
@@ -52,12 +52,12 @@
                 mCallbackCalled = true;
             }
         });
-        assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return mCallbackCalled;
             }
-        }));
+        });
         mCallbackCalled = false;
 
         ThreadUtils.runOnUiThreadBlocking(new Runnable() {
@@ -67,12 +67,12 @@
                         ClearBrowsingDataDialogFragment.FRAGMENT_TAG);
             }
         });
-        assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return mFragment.getDialog() != null;
             }
-        }));
+        });
 
         ThreadUtils.runOnUiThreadBlocking(new Runnable() {
             @Override
@@ -82,12 +82,12 @@
                 clearButton.performClick();
             }
         });
-        assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return mFragment.getProgressDialog() == null;
             }
-        }));
+        });
 
         WebappRegistry.getRegisteredWebappIds(getActivity(), new WebappRegistry.FetchCallback() {
             @Override
@@ -96,12 +96,12 @@
                 mCallbackCalled = true;
             }
         });
-        assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return mCallbackCalled;
             }
-        }));
+        });
     }
 
     private static class TestClearDataDialogFragment extends ClearBrowsingDataDialogFragment {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/prerender/PrerenderServiceTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/prerender/PrerenderServiceTest.java
index b69e555..63096878 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/prerender/PrerenderServiceTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/prerender/PrerenderServiceTest.java
@@ -146,15 +146,16 @@
                             }
                         });
         // TODO(yusufo): We should be using the NotificationCenter for checking the page loading.
-        assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
+        CriteriaHelper.pollForCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return chromeActivity.getActivityTab() != null
                         && chromeActivity.getActivityTab().isLoadingAndRenderingDone();
             }
-        }));
+        });
         assertTrue(chromeActivity.getActivityTab().getUrl().equals(url));
-        ThreadUtils.runOnUiThreadBlocking(new Runnable(){
+        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+            @Override
             public void run() {
                 assertFalse(WarmupManager.getInstance().hasAnyPrerenderedUrl());
             }
@@ -162,11 +163,11 @@
     }
 
     private void assertServiceHasPrerenderedUrl(final String url) throws InterruptedException {
-        assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return WarmupManager.getInstance().hasPrerenderedUrl(url);
             }
-        }));
+        });
     }
 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/search_engines/TemplateUrlServiceTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/search_engines/TemplateUrlServiceTest.java
index 9037daa..1aa9e85a 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/search_engines/TemplateUrlServiceTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/search_engines/TemplateUrlServiceTest.java
@@ -160,13 +160,13 @@
                     }
                 });
 
-        assertTrue("Observer wasn't notified of TemplateUrlService load.",
-                CriteriaHelper.pollForCriteria(new Criteria() {
-                    @Override
-                    public boolean isSatisfied() {
-                        return observerNotified.get();
-                    }
-                }));
+        CriteriaHelper.pollForCriteria(new Criteria(
+                "Observer wasn't notified of TemplateUrlService load.") {
+            @Override
+            public boolean isSatisfied() {
+                return observerNotified.get();
+            }
+        });
         return templateUrlService;
     }
 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/tab/InterceptNavigationDelegateTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/tab/InterceptNavigationDelegateTest.java
index f01645b..2b6e9b3 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/tab/InterceptNavigationDelegateTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/tab/InterceptNavigationDelegateTest.java
@@ -66,9 +66,9 @@
     }
 
     private void waitTillExpectedCallsComplete(final int count, long timeout) {
-        boolean result = false;
         try {
-            result = CriteriaHelper.pollForCriteria(new Criteria() {
+            CriteriaHelper.pollForCriteria(new Criteria(
+                    "Failed while waiting for all calls to complete.") {
                 @Override
                 public boolean isSatisfied() {
                     return mHistory.size() == count;
@@ -77,7 +77,6 @@
         } catch (InterruptedException e) {
             fail("Failed while waiting for all calls to complete." + e);
         }
-        assertTrue("Failed while waiting for all calls to complete.", result);
     }
 
     @Override
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/document/AsyncDocumentLauncherTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/document/AsyncDocumentLauncherTest.java
index 2b6b699..8326836 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/document/AsyncDocumentLauncherTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/document/AsyncDocumentLauncherTest.java
@@ -40,7 +40,7 @@
         AsyncDocumentLauncher.getInstance().enqueueLaunch(false, Tab.INVALID_TAB_ID, secondParams);
         AsyncDocumentLauncher.getInstance().enqueueLaunch(false, Tab.INVALID_TAB_ID, finalParams);
 
-        assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
+        CriteriaHelper.pollForCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 Activity lastActivity = ApplicationStatus.getLastTrackedFocusedActivity();
@@ -51,7 +51,7 @@
 
                 return TextUtils.equals(URL_3, documentActivity.getActivityTab().getUrl());
             }
-        }));
+        });
 
         TabModelSelector selector = ChromeApplication.getDocumentTabModelSelector();
         assertEquals(3, selector.getTotalTabCount());
@@ -74,7 +74,7 @@
         AsyncDocumentLauncher.getInstance().enqueueLaunch(false, parentId, secondParams);
         AsyncDocumentLauncher.getInstance().enqueueLaunch(false, parentId, finalParams);
 
-        assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
+        CriteriaHelper.pollForCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 Activity lastActivity = ApplicationStatus.getLastTrackedFocusedActivity();
@@ -85,7 +85,7 @@
 
                 return TextUtils.equals(URL_4, documentActivity.getActivityTab().getUrl());
             }
-        }));
+        });
 
         TabModelSelector selector = ChromeApplication.getDocumentTabModelSelector();
         assertEquals(4, selector.getTotalTabCount());
@@ -116,7 +116,7 @@
         AsyncDocumentLauncher.getInstance().enqueueLaunch(false, parentId, secondParams);
         AsyncDocumentLauncher.getInstance().enqueueLaunch(false, Tab.INVALID_TAB_ID, finalParams);
 
-        assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
+        CriteriaHelper.pollForCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 Activity lastActivity = ApplicationStatus.getLastTrackedFocusedActivity();
@@ -127,7 +127,7 @@
 
                 return TextUtils.equals(URL_4, documentActivity.getActivityTab().getUrl());
             }
-        }));
+        });
 
         TabModelSelector selector = ChromeApplication.getDocumentTabModelSelector();
         assertEquals(3, selector.getTotalTabCount());
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/BrandColorTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/BrandColorTest.java
index cbce4f5..84341a0 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/BrandColorTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/BrandColorTest.java
@@ -64,35 +64,35 @@
     @TargetApi(Build.VERSION_CODES.LOLLIPOP)
     private void checkForBrandColor(final int brandColor) {
         try {
-            assertTrue("The toolbar background doesn't contain the right color",
-                    CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
-                        @Override
-                        public boolean isSatisfied() {
-                            if (mToolbarDataProvider.getPrimaryColor() != brandColor) return false;
-                            return mToolbarDataProvider.getPrimaryColor()
-                                    == mToolbar.getBackgroundDrawable().getColor();
-                        }
-                    }));
-            assertTrue("The overlay drawable doesn't contain the right color",
-                    CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
-                        @Override
-                        public boolean isSatisfied() {
-                            return mToolbar.getOverlayDrawable().getColor() == brandColor;
-                        }
-                    }));
+            CriteriaHelper.pollForUIThreadCriteria(new Criteria(
+                    "The toolbar background doesn't contain the right color") {
+                @Override
+                public boolean isSatisfied() {
+                    if (mToolbarDataProvider.getPrimaryColor() != brandColor) return false;
+                    return mToolbarDataProvider.getPrimaryColor()
+                            == mToolbar.getBackgroundDrawable().getColor();
+                }
+            });
+            CriteriaHelper.pollForUIThreadCriteria(new Criteria(
+                    "The overlay drawable doesn't contain the right color") {
+                @Override
+                public boolean isSatisfied() {
+                    return mToolbar.getOverlayDrawable().getColor() == brandColor;
+                }
+            });
             if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP
                     && !SysUtils.isLowEndDevice()) {
                 final int expectedStatusBarColor = brandColor == mDefaultColor
                         ? Color.BLACK
                         : ColorUtils.getDarkenedColorForStatusBar(brandColor);
-                assertTrue("The status bar is not set to the right color",
-                        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
-                            @Override
-                            public boolean isSatisfied() {
-                                return expectedStatusBarColor
-                                        == getActivity().getWindow().getStatusBarColor();
-                            }
-                        }));
+                CriteriaHelper.pollForUIThreadCriteria(new Criteria(
+                        "The status bar is not set to the right color") {
+                    @Override
+                    public boolean isSatisfied() {
+                        return expectedStatusBarColor
+                                == getActivity().getWindow().getStatusBarColor();
+                    }
+                });
             }
 
         } catch (InterruptedException e) {
@@ -215,12 +215,12 @@
                         brandColorUrl, delegate.getNative());
             }
         });
-        assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return getActivity().getActivityTab().isShowingInterstitialPage();
             }
-        }));
+        });
         checkForBrandColor(ApiCompatibilityUtils.getColor(
                 getActivity().getResources(), R.color.default_primary_color));
     }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/ToolbarTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/ToolbarTest.java
index 2569edd..4950e795 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/ToolbarTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/ToolbarTest.java
@@ -42,7 +42,7 @@
     }
 
     private void waitForFindInPageVisibility(final boolean visible) throws InterruptedException {
-        assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 FindToolbar findToolbar = (FindToolbar) getActivity().findViewById(
@@ -51,7 +51,7 @@
                 boolean isVisible = findToolbar != null && findToolbar.isShown();
                 return (visible == isVisible) && !findToolbar.isAnimating();
             }
-        }));
+        });
     }
 
     @MediumTest
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/video/FullscreenVideoTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/video/FullscreenVideoTest.java
index 4991c4d..4d5373a 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/video/FullscreenVideoTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/video/FullscreenVideoTest.java
@@ -75,20 +75,20 @@
     }
 
     void waitForVideoToEnterFullscreen() throws InterruptedException {
-        assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
+        CriteriaHelper.pollForCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return mIsTabFullscreen;
             }
-        }, TEST_TIMEOUT, CriteriaHelper.DEFAULT_POLLING_INTERVAL));
+        }, TEST_TIMEOUT, CriteriaHelper.DEFAULT_POLLING_INTERVAL);
     }
 
     void waitForTabToExitFullscreen() throws InterruptedException {
-        assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
+        CriteriaHelper.pollForCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return !mIsTabFullscreen;
             }
-        }, TEST_TIMEOUT, CriteriaHelper.DEFAULT_POLLING_INTERVAL));
+        }, TEST_TIMEOUT, CriteriaHelper.DEFAULT_POLLING_INTERVAL);
     }
 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/AddToHomescreenDialogHelperTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/AddToHomescreenDialogHelperTest.java
index 4056420..553167a 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/AddToHomescreenDialogHelperTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/AddToHomescreenDialogHelperTest.java
@@ -201,12 +201,12 @@
         addShortcutToURL(MANIFEST_URL, MANIFEST_TITLE, "");
 
         // Make sure that the splash screen image was downloaded.
-        assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return dataStorageFactory.mSplashImage != null;
             }
-        }));
+        });
 
         // Test that bitmap sizes match expectations.
         int idealSize = mActivity.getResources().getDimensionPixelSize(
@@ -245,12 +245,12 @@
                 ThreadUtils.runOnUiThreadBlockingNoException(callable);
 
         // Make sure that the shortcut was added.
-        assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return mShortcutHelperDelegate.mBroadcastedIntent != null;
             }
-        }));
+        });
 
         ThreadUtils.runOnUiThreadBlocking(new Runnable() {
             @Override
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappActivityTestBase.java b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappActivityTestBase.java
index 29318bcf..39f0a40 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappActivityTestBase.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappActivityTestBase.java
@@ -126,7 +126,7 @@
     protected void waitUntilIdle() {
         getInstrumentation().waitForIdleSync();
         try {
-            assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
+            CriteriaHelper.pollForCriteria(new Criteria() {
                     @Override
                     public boolean isSatisfied() {
                         return getActivity().getActivityTab() != null
@@ -134,7 +134,7 @@
                     }
                 },
                 MultiActivityTestBase.DEFAULT_MAX_TIME_TO_POLL_FOR_ACTIVITY_MS,
-                CriteriaHelper.DEFAULT_POLLING_INTERVAL));
+                CriteriaHelper.DEFAULT_POLLING_INTERVAL);
         } catch (InterruptedException exception) {
             fail();
         }
@@ -184,15 +184,14 @@
     }
 
     /**
-     * Waits for the splash screen to be hidden and return whether it was hidden
-     * (true) or if it timed out (false).
+     * Waits for the splash screen to be hidden.
      */
-    protected boolean waitUntilSplashscreenHides() throws InterruptedException {
-        return CriteriaHelper.pollForCriteria(new Criteria() {
-                @Override
-                public boolean isSatisfied() {
-                    return !getActivity().isSplashScreenVisibleForTests();
-                }
-            });
+    protected void waitUntilSplashscreenHides() throws InterruptedException {
+        CriteriaHelper.pollForCriteria(new Criteria() {
+            @Override
+            public boolean isSatisfied() {
+                return !getActivity().isSplashScreenVisibleForTests();
+            }
+        });
     }
 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappDirectoryManagerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappDirectoryManagerTest.java
index 3ac7b29a..6fafa65c6 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappDirectoryManagerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappDirectoryManagerTest.java
@@ -156,11 +156,11 @@
     private void runCleanup() throws Exception {
         final AsyncTask task =
                 mWebappDirectoryManager.cleanUpDirectories(mMockContext, WEBAPP_ID_1);
-        assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
+        CriteriaHelper.pollForCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return task.getStatus() == AsyncTask.Status.FINISHED;
             }
-        }));
+        });
     }
 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappModeTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappModeTest.java
index 3f29466..5f23172 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappModeTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappModeTest.java
@@ -64,8 +64,8 @@
             + "IWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3wQIFB4cxOfiSQAAABl0RVh0Q29tbWVudABDcmVhdGVkIHdpdG"
             + "ggR0lNUFeBDhcAAAAMSURBVAjXY2AUawEAALcAnI/TkI8AAAAASUVORK5CYII=";
 
-    private boolean isNumberOfRunningActivitiesCorrect(final int numActivities) throws Exception {
-        return CriteriaHelper.pollForCriteria(new Criteria() {
+    private void isNumberOfRunningActivitiesCorrect(final int numActivities) throws Exception {
+        CriteriaHelper.pollForCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 Context context = getInstrumentation().getTargetContext();
@@ -126,29 +126,29 @@
     public void testWebappLaunches() throws Exception {
         final Activity firstActivity =
                 startWebappActivity(WEBAPP_1_ID, WEBAPP_1_URL, WEBAPP_1_TITLE, WEBAPP_ICON);
-        assertTrue(isNumberOfRunningActivitiesCorrect(1));
+        isNumberOfRunningActivitiesCorrect(1);
 
         // Firing a different Intent should start a new WebappActivity instance.
         fireWebappIntent(WEBAPP_2_ID, WEBAPP_2_URL, WEBAPP_2_TITLE, WEBAPP_ICON, true);
-        assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 Activity lastActivity = ApplicationStatus.getLastTrackedFocusedActivity();
                 return isWebappActivityReady(lastActivity) && lastActivity != firstActivity;
             }
-        }));
-        assertTrue(isNumberOfRunningActivitiesCorrect(2));
+        });
+        isNumberOfRunningActivitiesCorrect(2);
 
         // Firing the first Intent should bring back the first WebappActivity instance.
         fireWebappIntent(WEBAPP_1_ID, WEBAPP_1_URL, WEBAPP_1_TITLE, WEBAPP_ICON, true);
-        assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 Activity lastActivity = ApplicationStatus.getLastTrackedFocusedActivity();
                 return isWebappActivityReady(lastActivity) && lastActivity == firstActivity;
             }
-        }));
-        assertTrue(isNumberOfRunningActivitiesCorrect(2));
+        });
+        isNumberOfRunningActivitiesCorrect(2);
     }
 
     /**
@@ -164,7 +164,7 @@
 
         final WebappActivity webappActivity =
                 startWebappActivity(WEBAPP_1_ID, WEBAPP_1_URL, WEBAPP_1_TITLE, WEBAPP_ICON);
-        assertTrue(isNumberOfRunningActivitiesCorrect(1));
+        isNumberOfRunningActivitiesCorrect(1);
         assertEquals("Wrong Tab ID was used", 11684, webappActivity.getActivityTab().getId());
     }
 
@@ -196,7 +196,7 @@
         // Start the WebappActivity.
         final WebappActivity activity =
                 startWebappActivity(WEBAPP_1_ID, WEBAPP_1_URL, WEBAPP_1_TITLE, WEBAPP_ICON);
-        assertTrue(isNumberOfRunningActivitiesCorrect(1));
+        isNumberOfRunningActivitiesCorrect(1);
 
         // Return home.
         final Context context = getInstrumentation().getTargetContext();
@@ -217,14 +217,14 @@
         // When Chrome is back in the foreground, confirm that the original Activity was restored.
         getInstrumentation().waitForIdleSync();
         ApplicationTestUtils.waitUntilChromeInForeground();
-        assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
+        CriteriaHelper.pollForCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return activity == ApplicationStatus.getLastTrackedFocusedActivity()
                         && activity.hasWindowFocus();
             }
-        }));
-        assertTrue(isNumberOfRunningActivitiesCorrect(1));
+        });
+        isNumberOfRunningActivitiesCorrect(1);
     }
 
     /**
@@ -234,7 +234,7 @@
     public void testWebappRequiresValidMac() throws Exception {
         // Try to start a WebappActivity.  Fail because the Intent is insecure.
         fireWebappIntent(WEBAPP_1_ID, WEBAPP_1_URL, WEBAPP_1_TITLE, WEBAPP_ICON, false);
-        assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 Activity lastActivity = ApplicationStatus.getLastTrackedFocusedActivity();
@@ -242,18 +242,18 @@
                 return lastActivity instanceof ChromeTabbedActivity
                         || lastActivity instanceof DocumentActivity;
             }
-        }));
+        });
         final Activity firstActivity = ApplicationStatus.getLastTrackedFocusedActivity();
 
         // Firing a correct Intent should start a new WebappActivity instance.
         fireWebappIntent(WEBAPP_2_ID, WEBAPP_2_URL, WEBAPP_2_TITLE, WEBAPP_ICON, true);
-        assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 Activity lastActivity = ApplicationStatus.getLastTrackedFocusedActivity();
                 return isWebappActivityReady(lastActivity) && lastActivity != firstActivity;
             }
-        }));
+        });
     }
 
     /**
@@ -296,7 +296,7 @@
             Class<T> classToWaitFor, String linkHtml, boolean checkContents) throws Exception {
         final WebappActivity webappActivity =
                 startWebappActivity(WEBAPP_1_ID, WEBAPP_1_URL, WEBAPP_1_TITLE, WEBAPP_ICON);
-        assertTrue(isNumberOfRunningActivitiesCorrect(1));
+        isNumberOfRunningActivitiesCorrect(1);
 
         // Load up the test page.
         new TabLoadObserver(webappActivity.getActivityTab(), linkHtml).assertLoaded(
@@ -330,12 +330,12 @@
         // Close the child window to kick the user back to the WebappActivity.
         JavaScriptUtils.executeJavaScript(
                 secondActivity.getActivityTab().getWebContents(), "window.close()");
-        assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return webappActivity == ApplicationStatus.getLastTrackedFocusedActivity();
             }
-        }));
+        });
         ApplicationTestUtils.waitUntilChromeInForeground();
     }
 
@@ -347,13 +347,13 @@
     private WebappActivity startWebappActivity(String id, String url, String title, String icon)
             throws Exception {
         fireWebappIntent(id, url, title, icon, true);
-        assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 Activity lastActivity = ApplicationStatus.getLastTrackedFocusedActivity();
                 return isWebappActivityReady(lastActivity);
             }
-        }));
+        });
         return (WebappActivity) ApplicationStatus.getLastTrackedFocusedActivity();
     }
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappSplashScreenTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappSplashScreenTest.java
index db1a9d2..aff1ce04 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappSplashScreenTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappSplashScreenTest.java
@@ -86,7 +86,7 @@
             }
         });
 
-        assertTrue(waitUntilSplashscreenHides());
+        waitUntilSplashscreenHides();
     }
 
     @SmallTest
@@ -102,7 +102,7 @@
             }
         });
 
-        assertTrue(waitUntilSplashscreenHides());
+        waitUntilSplashscreenHides();
     }
 
     @SmallTest
@@ -118,7 +118,7 @@
             }
         });
 
-        assertTrue(waitUntilSplashscreenHides());
+        waitUntilSplashscreenHides();
     }
 
     @SmallTest
@@ -134,7 +134,7 @@
             }
         });
 
-        assertTrue(waitUntilSplashscreenHides());
+        waitUntilSplashscreenHides();
     }
 
     @SmallTest
@@ -154,7 +154,7 @@
             }
         });
 
-        assertTrue(waitUntilSplashscreenHides());
+        waitUntilSplashscreenHides();
     }
 
     @SmallTest
@@ -201,7 +201,7 @@
             }
         });
 
-        assertTrue(waitUntilSplashscreenHides());
+        waitUntilSplashscreenHides();
 
         // DURATION and HIDES should now have a value.
         assertTrue(hasHistogramEntry(WebappUma.HISTOGRAM_SPLASHSCREEN_DURATION, 3000));
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappSplashScreenThemeColorTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappSplashScreenThemeColorTest.java
index 3bfecf3..d6600c91 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappSplashScreenThemeColorTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappSplashScreenThemeColorTest.java
@@ -63,13 +63,13 @@
         });
 
         // Waits for theme-color to change so the test doesn't rely on system timing.
-        assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
-                @Override
-                public boolean isSatisfied() {
-                    return getActivity().getWindow().getStatusBarColor()
-                            == ColorUtils.getDarkenedColorForStatusBar(Color.GREEN);
-                }
-            }));
+        CriteriaHelper.pollForCriteria(new Criteria() {
+            @Override
+            public boolean isSatisfied() {
+                return getActivity().getWindow().getStatusBarColor()
+                        == ColorUtils.getDarkenedColorForStatusBar(Color.GREEN);
+            }
+        });
     }
 
     @SmallTest
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/widget/OverviewListLayoutTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/widget/OverviewListLayoutTest.java
index 7cb2600..984fcfc5 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/widget/OverviewListLayoutTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/widget/OverviewListLayoutTest.java
@@ -49,7 +49,7 @@
     private static final int SWIPE_START_Y_OFFSET = 10;
     private static final int SWIPE_END_X = 20;
 
-    private class ChildCountCriteria implements Criteria {
+    private class ChildCountCriteria extends Criteria {
         private final int mChildCount;
 
         public ChildCountCriteria(int count) {
@@ -68,7 +68,7 @@
         }
     }
 
-    private class TabModelCountCountCriteria implements Criteria {
+    private class TabModelCountCountCriteria extends Criteria {
         private final boolean mIncognito;
         private final int mTabCount;
 
@@ -79,7 +79,7 @@
 
         @Override
         public boolean isSatisfied() {
-            return mTabCount == ThreadUtils.runOnUiThreadBlockingNoException(
+            int actualTabCount = ThreadUtils.runOnUiThreadBlockingNoException(
                     new Callable<Integer>() {
                         @Override
                         public Integer call() {
@@ -87,6 +87,8 @@
                                     .getModel(mIncognito).getCount();
                         }
                     });
+            updateFailureReason("Expected tab count: " + mTabCount + ", Actual: " + actualTabCount);
+            return mTabCount == actualTabCount;
         }
     }
 
@@ -110,8 +112,7 @@
         TestTouchUtils.performClickOnMainSync(
                 getInstrumentation(), getActivity().findViewById(R.id.tab_switcher_button));
 
-        assertTrue(
-                "Wrong number of tabs", CriteriaHelper.pollForCriteria(new ChildCountCriteria(4)));
+        CriteriaHelper.pollForCriteria(new ChildCountCriteria(4));
     }
 
     private AccessibilityTabModelListItem getListItemAndDisableAnimations(int index) {
@@ -136,13 +137,13 @@
     private void toggleTabSwitcher(final boolean expectVisible) throws Exception {
         TestTouchUtils.performClickOnMainSync(
                 getInstrumentation(), getActivity().findViewById(R.id.tab_switcher_button));
-        assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 boolean isVisible = (getContainer() != null && getContainer().getParent() != null);
                 return isVisible == expectVisible;
             }
-        }));
+        });
     }
 
     @Restriction(RESTRICTION_TYPE_PHONE)
@@ -301,10 +302,8 @@
         MenuUtils.invokeCustomMenuActionSync(
                 getInstrumentation(), getActivity(), R.id.close_all_tabs_menu_id);
 
-        assertTrue(
-                "Wrong number of tabs", CriteriaHelper.pollForCriteria(new ChildCountCriteria(0)));
-        assertTrue("Tabs not closed on the model",
-                CriteriaHelper.pollForCriteria(new TabModelCountCountCriteria(false, 0)));
+        CriteriaHelper.pollForCriteria(new ChildCountCriteria(0));
+        CriteriaHelper.pollForCriteria(new TabModelCountCountCriteria(false, 0));
         assertFalse(getActivity().findViewById(R.id.tab_switcher_button).isEnabled());
     }
 
@@ -316,25 +315,20 @@
         newIncognitoTabsFromMenu(2);
         TestTouchUtils.performClickOnMainSync(
                 getInstrumentation(), getActivity().findViewById(R.id.tab_switcher_button));
-        assertTrue(
-                "Wrong number of tabs", CriteriaHelper.pollForCriteria(new ChildCountCriteria(2)));
+        CriteriaHelper.pollForCriteria(new ChildCountCriteria(2));
 
         MenuUtils.invokeCustomMenuActionSync(
                 getInstrumentation(), getActivity(), R.id.close_all_incognito_tabs_menu_id);
-        assertTrue("Tabs not closed on the model",
-                CriteriaHelper.pollForCriteria(new TabModelCountCountCriteria(true, 0)));
+        CriteriaHelper.pollForCriteria(new TabModelCountCountCriteria(true, 0));
 
-        assertTrue(
-                "Wrong number of tabs", CriteriaHelper.pollForCriteria(new ChildCountCriteria(4)));
+        CriteriaHelper.pollForCriteria(new ChildCountCriteria(4));
         assertTrue(getActivity().findViewById(R.id.tab_switcher_button).isEnabled());
 
         MenuUtils.invokeCustomMenuActionSync(
                 getInstrumentation(), getActivity(), R.id.close_all_tabs_menu_id);
 
-        assertTrue(
-                "Wrong number of tabs", CriteriaHelper.pollForCriteria(new ChildCountCriteria(0)));
-        assertTrue("Tabs not closed on the model",
-                CriteriaHelper.pollForCriteria(new TabModelCountCountCriteria(false, 0)));
+        CriteriaHelper.pollForCriteria(new ChildCountCriteria(0));
+        CriteriaHelper.pollForCriteria(new TabModelCountCountCriteria(false, 0));
         assertFalse(getActivity().findViewById(R.id.tab_switcher_button).isEnabled());
     }
 
@@ -380,14 +374,12 @@
 
         TestTouchUtils.performClickOnMainSync(getInstrumentation(), incognitoButton);
 
-        assertTrue(
-                "Wrong number of tabs", CriteriaHelper.pollForCriteria(new ChildCountCriteria(2)));
+        CriteriaHelper.pollForCriteria(new ChildCountCriteria(2));
 
         TestTouchUtils.performClickOnMainSync(
                 getInstrumentation(), switcherButtons.findViewById(R.id.standard_tabs_button));
 
-        assertTrue(
-                "Wrong number of tabs", CriteriaHelper.pollForCriteria(new ChildCountCriteria(4)));
+        CriteriaHelper.pollForCriteria(new ChildCountCriteria(4));
     }
 
     /**
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/widget/findinpage/FindTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/widget/findinpage/FindTest.java
index 163b5c9..c1aeeb8 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/widget/findinpage/FindTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/widget/findinpage/FindTest.java
@@ -47,12 +47,12 @@
         final TextView findResults = (TextView) getActivity().findViewById(R.id.find_status);
         assertNotNull(expectedResult);
         assertNotNull(findResults);
-        assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
                 @Override
                 public boolean isSatisfied() {
                     return expectedResult.equals(findResults.getText());
                 }
-            }));
+            });
         return findResults.getText().toString();
     }
 
@@ -69,7 +69,7 @@
     }
 
     private void waitForFindInPageVisibility(final boolean visible) throws InterruptedException {
-        assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 FindToolbar findToolbar = (FindToolbar) getActivity().findViewById(
@@ -78,7 +78,7 @@
                 boolean isVisible = findToolbar != null && findToolbar.isShown();
                 return (visible == isVisible) && !findToolbar.isAnimating();
             }
-        }));
+        });
     }
 
     private String findStringInPage(final String query, String expectedResult)
diff --git a/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/AutofillTest.java b/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/AutofillTest.java
index d4eca1e..b529e9d 100644
--- a/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/AutofillTest.java
+++ b/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/AutofillTest.java
@@ -174,7 +174,8 @@
     }
 
     private void waitForClientAutofillProfileCount(final int count) throws InterruptedException {
-        boolean success = CriteriaHelper.pollForCriteria(new Criteria() {
+        CriteriaHelper.pollForCriteria(new Criteria(
+                "Expected " + count + " local autofill profiles.") {
             @Override
             public boolean isSatisfied() {
                 try {
@@ -184,12 +185,12 @@
                 }
             }
         }, SyncTestUtil.TIMEOUT_MS, SyncTestUtil.INTERVAL_MS);
-        assertTrue("Expected " + count + " local autofill profiles.", success);
     }
 
     private void waitForServerAutofillProfileCountWithName(final int count, final String name)
             throws InterruptedException {
-        boolean success = CriteriaHelper.pollForCriteria(new Criteria() {
+        CriteriaHelper.pollForCriteria(new Criteria(
+                "Expected " + count + " server autofill profiles with name " + name + ".") {
             @Override
             public boolean isSatisfied() {
                 try {
@@ -200,7 +201,5 @@
                 }
             }
         }, SyncTestUtil.TIMEOUT_MS, SyncTestUtil.INTERVAL_MS);
-        assertTrue("Expected " + count + " server autofill profiles with name " + name + ".",
-                success);
     }
 }
diff --git a/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/BookmarksTest.java b/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/BookmarksTest.java
index 8caf1443..adbe3f1 100644
--- a/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/BookmarksTest.java
+++ b/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/BookmarksTest.java
@@ -456,7 +456,7 @@
     }
 
     private void waitForClientBookmarkCount(final int n) throws InterruptedException {
-        boolean success = CriteriaHelper.pollForCriteria(new Criteria() {
+        CriteriaHelper.pollForCriteria(new Criteria("There should be " + n + " local bookmarks.") {
             @Override
             public boolean isSatisfied() {
                 try {
@@ -466,12 +466,12 @@
                 }
             }
         }, SyncTestUtil.TIMEOUT_MS, SyncTestUtil.INTERVAL_MS);
-        assertTrue("There should be " + n + " local bookmarks.", success);
     }
 
     private void waitForServerBookmarkCountWithName(final int count, final String name)
             throws InterruptedException {
-        boolean success = CriteriaHelper.pollForCriteria(new Criteria() {
+        CriteriaHelper.pollForCriteria(new Criteria(
+                "Expected " + count + " remote bookmarks with name " + name + ".") {
             @Override
             public boolean isSatisfied() {
                 try {
@@ -482,6 +482,5 @@
                 }
             }
         }, SyncTestUtil.TIMEOUT_MS, SyncTestUtil.INTERVAL_MS);
-        assertTrue("Expected " + count + " remote bookmarks with name " + name + ".", success);
     }
 }
diff --git a/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/GmsCoreSyncListenerTest.java b/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/GmsCoreSyncListenerTest.java
index 84c6377..a41ca09 100644
--- a/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/GmsCoreSyncListenerTest.java
+++ b/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/GmsCoreSyncListenerTest.java
@@ -106,7 +106,8 @@
     }
 
     private void waitForCryptographer() throws InterruptedException {
-        boolean isReady = CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria(
+                "Timed out waiting for cryptographer to be ready.") {
             @Override
             public boolean isSatisfied() {
                 ProfileSyncService syncService = ProfileSyncService.get();
@@ -114,7 +115,6 @@
                         && syncService.isCryptographerReady();
             }
         });
-        assertTrue("Timed out waiting for cryptographer to be ready.", isReady);
     }
 
     private void waitForCallCount(final int count) throws InterruptedException {
diff --git a/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/OpenTabsTest.java b/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/OpenTabsTest.java
index a4d58d4f..b591002 100644
--- a/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/OpenTabsTest.java
+++ b/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/OpenTabsTest.java
@@ -245,7 +245,9 @@
             throws InterruptedException {
         final List<String> urlList = new ArrayList<String>(urls.length);
         for (String url : urls) urlList.add(url);
-        boolean success = CriteriaHelper.pollForCriteria(new Criteria() {
+        CriteriaHelper.pollForCriteria(new Criteria(
+                "Expected local open tabs for client " + clientName + ": "
+                        + Arrays.toString(urls)) {
             @Override
             public boolean isSatisfied() {
                 try {
@@ -255,13 +257,12 @@
                 }
             }
         }, SyncTestUtil.TIMEOUT_MS, SyncTestUtil.INTERVAL_MS);
-        assertTrue("Expected local open tabs for client " + clientName + ": "
-                + Arrays.toString(urls), success);
     }
 
     private void waitForServerTabs(final String... urls)
             throws InterruptedException {
-        boolean success = CriteriaHelper.pollForCriteria(new Criteria() {
+        CriteriaHelper.pollForCriteria(new Criteria(
+                "Expected server open tabs: " + Arrays.toString(urls)) {
             @Override
             public boolean isSatisfied() {
                 try {
@@ -271,7 +272,6 @@
                 }
             }
         }, SyncTestUtil.TIMEOUT_MS, SyncTestUtil.INTERVAL_MS);
-        assertTrue("Expected server open tabs: " + Arrays.toString(urls), success);
     }
 
     private String getClientName() throws JSONException {
diff --git a/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/SyncCustomizationFragmentTest.java b/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/SyncCustomizationFragmentTest.java
index 0d8db0ae..6b00ee1d 100644
--- a/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/SyncCustomizationFragmentTest.java
+++ b/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/SyncCustomizationFragmentTest.java
@@ -523,13 +523,13 @@
     }
 
     private void waitForBackendInitialized() throws InterruptedException {
-        boolean success = CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria(
+                "Timed out waiting for sync's backend to be initialized.") {
             @Override
             public boolean isSatisfied() {
                 return mProfileSyncService.isBackendInitialized();
             }
         }, SyncTestUtil.TIMEOUT_MS, SyncTestUtil.INTERVAL_MS);
-        assertTrue("Timed out waiting for sync's backend to be initialized.", success);
     }
 
     // UI interaction convenience methods.
diff --git a/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/SyncTest.java b/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/SyncTest.java
index 3ac169e..33bc734 100644
--- a/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/SyncTest.java
+++ b/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/SyncTest.java
@@ -66,7 +66,7 @@
 
     @LargeTest
     @Feature({"Sync"})
-    public void testDisableAndEnableSyncThroughAndroid() throws InterruptedException {
+    public void testStopAndStartSyncThroughAndroid() throws InterruptedException {
         Account account = setUpTestAccountAndSignInToSync();
         SyncTestUtil.waitForSyncActive();
 
@@ -79,6 +79,27 @@
         // Enabling Android sync should turn Chrome sync engine on.
         mSyncContentResolver.setSyncAutomatically(account, authority, true);
         SyncTestUtil.verifySyncIsActiveForAccount(mContext, account);
+
+        // Disabling Android's master sync should turn Chrome sync engine off.
+        mSyncContentResolver.setMasterSyncAutomatically(false);
+        SyncTestUtil.verifySyncIsDisabled(mContext, account);
+
+        // Enabling Android's master sync should turn Chrome sync engine on.
+        mSyncContentResolver.setMasterSyncAutomatically(true);
+        SyncTestUtil.verifySyncIsActiveForAccount(mContext, account);
+
+        // Disabling both should definitely turn sync off.
+        mSyncContentResolver.setSyncAutomatically(account, authority, false);
+        mSyncContentResolver.setMasterSyncAutomatically(false);
+        SyncTestUtil.verifySyncIsDisabled(mContext, account);
+
+        // Re-enabling master sync should not turn sync back on.
+        mSyncContentResolver.setMasterSyncAutomatically(true);
+        SyncTestUtil.verifySyncIsDisabled(mContext, account);
+
+        // But then re-enabling Chrome sync should.
+        mSyncContentResolver.setSyncAutomatically(account, authority, true);
+        SyncTestUtil.verifySyncIsActiveForAccount(mContext, account);
     }
 
     private static ContentViewCore getContentViewCore(ChromeActivity activity) {
diff --git a/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/SyncTestBase.java b/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/SyncTestBase.java
index fd59063..1eb72c1 100644
--- a/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/SyncTestBase.java
+++ b/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/SyncTestBase.java
@@ -13,6 +13,7 @@
 import org.chromium.chrome.browser.identity.UniqueIdentificationGeneratorFactory;
 import org.chromium.chrome.browser.identity.UuidBasedUniqueIdentificationGenerator;
 import org.chromium.chrome.browser.signin.SigninManager;
+import org.chromium.chrome.browser.signin.SigninManager.SignInFlowObserver;
 import org.chromium.chrome.test.ChromeActivityTestCaseBase;
 import org.chromium.chrome.test.util.browser.signin.SigninTestUtil;
 import org.chromium.chrome.test.util.browser.sync.SyncTestUtil;
@@ -47,7 +48,6 @@
             }));
 
     protected Context mContext;
-    protected SyncController mSyncController;
     protected FakeServerHelper mFakeServerHelper;
     protected ProfileSyncService mProfileSyncService;
     protected MockSyncContentResolverDelegate mSyncContentResolver;
@@ -76,9 +76,8 @@
         ThreadUtils.runOnUiThreadBlocking(new Runnable() {
             @Override
             public void run() {
-                mSyncController = SyncController.get(mContext);
                 // Ensure SyncController is registered with the new AndroidSyncSettings.
-                AndroidSyncSettings.registerObserver(mContext, mSyncController);
+                AndroidSyncSettings.registerObserver(mContext, SyncController.get(mContext));
                 mFakeServerHelper = FakeServerHelper.get();
             }
         });
@@ -105,7 +104,7 @@
         ThreadUtils.runOnUiThreadBlocking(new Runnable() {
             @Override
             public void run() {
-                mSyncController.stop();
+                mProfileSyncService.requestStop();
                 FakeServerHelper.deleteFakeServer();
             }
         });
@@ -136,7 +135,7 @@
         ThreadUtils.runOnUiThreadBlocking(new Runnable() {
             @Override
             public void run() {
-                SyncController.get(mContext).start();
+                mProfileSyncService.requestStart();
             }
         });
         SyncTestUtil.waitForSyncActive();
@@ -146,7 +145,7 @@
         ThreadUtils.runOnUiThreadBlocking(new Runnable() {
             @Override
             public void run() {
-                SyncController.get(mContext).stop();
+                mProfileSyncService.requestStop();
             }
         });
         getInstrumentation().waitForIdleSync();
@@ -156,7 +155,17 @@
         ThreadUtils.runOnUiThreadBlocking(new Runnable() {
             @Override
             public void run() {
-                mSyncController.signIn(getActivity(), account.name);
+                SigninManager signinManager = SigninManager.get(mContext);
+                signinManager.startSignIn(null, account, false, new SignInFlowObserver() {
+                    @Override
+                    public void onSigninComplete() {
+                        mProfileSyncService.requestStart();
+                    }
+
+                    @Override
+                    public void onSigninCancelled() {
+                    }
+                });
             }
         });
         SyncTestUtil.verifySyncIsActiveForAccount(mContext, account);
@@ -182,13 +191,12 @@
     protected void clearServerData() throws InterruptedException {
         mFakeServerHelper.clearServerData();
         SyncTestUtil.triggerSync();
-        boolean syncStopped = CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria("Timed out waiting for sync to stop.") {
             @Override
             public boolean isSatisfied() {
                 return !ProfileSyncService.get().isSyncRequested();
             }
         }, SyncTestUtil.TIMEOUT_MS, SyncTestUtil.INTERVAL_MS);
-        assertTrue("Timed out waiting for sync to stop.", syncStopped);
     }
 
     protected void disableDataType(final int modelType) {
diff --git a/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/TypedUrlsTest.java b/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/TypedUrlsTest.java
index f76f5c3..f982a3d 100644
--- a/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/TypedUrlsTest.java
+++ b/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/TypedUrlsTest.java
@@ -142,7 +142,8 @@
     }
 
     private void waitForClientTypedUrlCount(final int count) throws InterruptedException {
-        boolean success = CriteriaHelper.pollForCriteria(new Criteria() {
+        CriteriaHelper.pollForCriteria(new Criteria(
+                "Expected " + count + " local typed URL entities.") {
             @Override
             public boolean isSatisfied() {
                 try {
@@ -152,12 +153,12 @@
                 }
             }
         }, SyncTestUtil.TIMEOUT_MS, SyncTestUtil.INTERVAL_MS);
-        assertTrue("Expected " + count + " local typed URL entities.", success);
     }
 
     private void waitForServerTypedUrlCountWithName(final int count, final String name)
             throws InterruptedException {
-        boolean success = CriteriaHelper.pollForCriteria(new Criteria() {
+        CriteriaHelper.pollForCriteria(new Criteria(
+                "Expected " + count + " server typed URLs with name " + name + ".") {
             @Override
             public boolean isSatisfied() {
                 try {
@@ -168,6 +169,5 @@
                 }
             }
         }, SyncTestUtil.TIMEOUT_MS, SyncTestUtil.INTERVAL_MS);
-        assertTrue("Expected " + count + " server typed URLs with name " + name + ".", success);
     }
 }
diff --git a/chrome/app/chrome_crash_reporter_client.cc b/chrome/app/chrome_crash_reporter_client.cc
index 2663a08..4cac4f1 100644
--- a/chrome/app/chrome_crash_reporter_client.cc
+++ b/chrome/app/chrome_crash_reporter_client.cc
@@ -16,6 +16,7 @@
 #include "chrome/common/chrome_result_codes.h"
 #include "chrome/common/crash_keys.h"
 #include "chrome/common/env_vars.h"
+#include "chrome/installer/util/browser_distribution.h"
 #include "chrome/installer/util/google_update_settings.h"
 #include "content/public/common/content_switches.h"
 
@@ -278,6 +279,22 @@
 
 bool ChromeCrashReporterClient::GetCrashDumpLocation(
     base::FilePath* crash_dir) {
+#if defined(OS_WIN)
+  // In order to be able to start crash handling very early, we do not rely on
+  // chrome's PathService entries (for DIR_CRASH_DUMPS) being available on
+  // Windows. See https://crbug.com/564398.
+  base::FilePath result;
+  if (!PathService::Get(base::DIR_LOCAL_APP_DATA, &result))
+    return false;
+  BrowserDistribution* dist = BrowserDistribution::GetDistribution();
+  result = result.Append(dist->GetInstallSubDir());
+  // TODO(scottmg): Consider supporting --user-data-dir. See
+  // https://crbug.com/565446.
+  result = result.Append(chrome::kUserDataDirname);
+  result = result.Append(FILE_PATH_LITERAL("Crashpad"));
+  *crash_dir = result;
+  return true;
+#else
   // By setting the BREAKPAD_DUMP_LOCATION environment variable, an alternate
   // location to write breakpad crash dumps can be set.
   scoped_ptr<base::Environment> env(base::Environment::Create());
@@ -289,6 +306,7 @@
   }
 
   return PathService::Get(chrome::DIR_CRASH_DUMPS, crash_dir);
+#endif
 }
 
 size_t ChromeCrashReporterClient::RegisterCrashKeys() {
diff --git a/chrome/app/chrome_exe_main_win.cc b/chrome/app/chrome_exe_main_win.cc
index cf91743e..c052283 100644
--- a/chrome/app/chrome_exe_main_win.cc
+++ b/chrome/app/chrome_exe_main_win.cc
@@ -13,16 +13,20 @@
 #include "base/at_exit.h"
 #include "base/command_line.h"
 #include "base/files/file_path.h"
+#include "base/lazy_instance.h"
 #include "base/logging.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/time/time.h"
 #include "base/win/windows_version.h"
+#include "chrome/app/chrome_crash_reporter_client.h"
 #include "chrome/app/main_dll_loader_win.h"
 #include "chrome/browser/chrome_process_finder_win.h"
 #include "chrome/browser/policy/policy_path_parser.h"
 #include "chrome/common/chrome_paths_internal.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome_elf/chrome_elf_main.h"
+#include "components/crash/content/app/crash_reporter_client.h"
+#include "components/crash/content/app/crashpad.h"
 #include "components/startup_metric_utils/browser/startup_metric_utils.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/common/result_codes.h"
@@ -30,6 +34,13 @@
 #include "ui/gfx/win/dpi.h"
 
 namespace {
+
+base::LazyInstance<ChromeCrashReporterClient>::Leaky g_chrome_crash_client =
+    LAZY_INSTANCE_INITIALIZER;
+
+base::LazyInstance<std::vector<crash_reporter::UploadedReport>>::Leaky
+    g_uploaded_reports = LAZY_INSTANCE_INITIALIZER;
+
 // List of switches that it's safe to rendezvous early with. Fast start should
 // not be done if a command line contains a switch not in this set.
 // Note this is currently stored as a list of two because it's probably faster
@@ -125,46 +136,61 @@
   }
 }
 
-bool RunAsCrashpadHandler(wchar_t* command_line, int* rc) {
-  const base::CommandLine cmdline = base::CommandLine::FromString(command_line);
-  if (cmdline.GetSwitchValueASCII(switches::kProcessType) ==
-      switches::kCrashpadHandler) {
-    std::vector<base::string16> argv = cmdline.argv();
-    base::string16 process_type =
-        L"--" + base::UTF8ToUTF16(switches::kProcessType) + L"=";
-    argv.erase(std::remove_if(argv.begin(), argv.end(),
-                              [&process_type](const base::string16& str) {
-                                return str.compare(0, process_type.size(),
-                                                   process_type) == 0;
-                              }),
-               argv.end());
+int RunAsCrashpadHandler(const base::CommandLine& command_line) {
+  std::vector<base::string16> argv = command_line.argv();
+  base::string16 process_type =
+      L"--" + base::UTF8ToUTF16(switches::kProcessType) + L"=";
+  argv.erase(std::remove_if(argv.begin(), argv.end(),
+                            [&process_type](const base::string16& str) {
+                              return str.compare(0, process_type.size(),
+                                                 process_type) == 0;
+                            }),
+             argv.end());
 
-    scoped_ptr<char* []> argv_as_utf8(new char*[argv.size() + 1]);
-    std::vector<std::string> storage;
-    storage.reserve(argv.size());
-    for (size_t i = 0; i < argv.size(); ++i) {
-      storage.push_back(base::UTF16ToUTF8(argv[i]));
-      argv_as_utf8[i] = &storage[i][0];
-    }
-    argv_as_utf8[argv.size()] = nullptr;
-    *rc = crashpad::HandlerMain(static_cast<int>(argv.size()),
-                                argv_as_utf8.get());
-    return true;
+  scoped_ptr<char* []> argv_as_utf8(new char*[argv.size() + 1]);
+  std::vector<std::string> storage;
+  storage.reserve(argv.size());
+  for (size_t i = 0; i < argv.size(); ++i) {
+    storage.push_back(base::UTF16ToUTF8(argv[i]));
+    argv_as_utf8[i] = &storage[i][0];
   }
-  return false;
+  argv_as_utf8[argv.size()] = nullptr;
+  return crashpad::HandlerMain(static_cast<int>(argv.size()),
+                               argv_as_utf8.get());
 }
 
 }  // namespace
 
+// This helper is looked up in the browser to retrieve the crash reports. See
+// CrashUploadListCrashpad. Note that we do not pass an std::vector here,
+// because we do not want to allocate/free in different modules. The returned
+// pointer is read-only.
+extern "C" __declspec(dllexport) void GetUploadedReportsImpl(
+    const crash_reporter::UploadedReport** reports,
+    size_t* report_count) {
+  crash_reporter::GetUploadedReports(g_uploaded_reports.Pointer());
+  *reports = g_uploaded_reports.Pointer()->data();
+  *report_count = g_uploaded_reports.Pointer()->size();
+}
+
 #if !defined(WIN_CONSOLE_APP)
 int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE prev, wchar_t*, int) {
 #else
 int main() {
-  HINSTANCE instance = GetModuleHandle(NULL);
+  HINSTANCE instance = GetModuleHandle(nullptr);
 #endif
-  int rc;
-  if (RunAsCrashpadHandler(GetCommandLine(), &rc))
-    return rc;
+  // Initialize the CommandLine singleton from the environment.
+  base::CommandLine::Init(0, nullptr);
+
+  std::string process_type =
+      base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+          switches::kProcessType);
+
+  if (process_type == switches::kCrashpadHandler)
+    return RunAsCrashpadHandler(*base::CommandLine::ForCurrentProcess());
+
+  crash_reporter::SetCrashReporterClient(g_chrome_crash_client.Pointer());
+  crash_reporter::InitializeCrashpad(process_type.empty(), process_type);
 
   SwitchToLFHeap();
 
@@ -173,8 +199,6 @@
   // Signal Chrome Elf that Chrome has begun to start.
   SignalChromeElf();
 
-  // Initialize the commandline singleton from the environment.
-  base::CommandLine::Init(0, NULL);
   // The exit manager is in charge of calling the dtors of singletons.
   base::AtExitManager exit_manager;
 
@@ -190,7 +214,7 @@
   // Load and launch the chrome dll. *Everything* happens inside.
   VLOG(1) << "About to load main DLL.";
   MainDllLoader* loader = MakeMainDllLoader();
-  rc = loader->Launch(instance);
+  int rc = loader->Launch(instance);
   loader->RelaunchChromeBrowserWithNewCommandLineIfNeeded();
   delete loader;
   return rc;
diff --git a/chrome/app/chrome_main_delegate.cc b/chrome/app/chrome_main_delegate.cc
index 2d8b3951..f61a4a56 100644
--- a/chrome/app/chrome_main_delegate.cc
+++ b/chrome/app/chrome_main_delegate.cc
@@ -31,6 +31,7 @@
 #include "chrome/common/chrome_result_codes.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/crash_keys.h"
+#include "chrome/common/features.h"
 #include "chrome/common/logging_chrome.h"
 #include "chrome/common/profiling.h"
 #include "chrome/common/switch_utils.h"
@@ -89,8 +90,11 @@
 #include "chromeos/chromeos_switches.h"
 #endif
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
 #include "chrome/browser/android/java_exception_reporter.h"
+#endif
+
+#if defined(OS_ANDROID)
 #include "chrome/common/descriptors_android.h"
 #else
 // Diagnostics is only available on non-android platforms.
@@ -146,7 +150,7 @@
     LAZY_INSTANCE_INITIALIZER;
 #endif
 
-#if defined(OS_POSIX) || defined(OS_WIN)
+#if defined(OS_POSIX)
 base::LazyInstance<ChromeCrashReporterClient>::Leaky g_chrome_crash_client =
     LAZY_INSTANCE_INITIALIZER;
 #endif
@@ -665,7 +669,7 @@
   std::string process_type =
       command_line.GetSwitchValueASCII(switches::kProcessType);
 
-#if defined(OS_POSIX) || defined(OS_WIN)
+#if defined(OS_POSIX)
   crash_reporter::SetCrashReporterClient(g_chrome_crash_client.Pointer());
 #endif
 
@@ -680,16 +684,6 @@
 #endif
 
 #if defined(OS_WIN)
-  // TODO(scottmg): It would be nice to do this earlier to catch early crashes,
-  // perhaps as early as WinMain in chrome.exe. This would require some code
-  // restructuring to have paths and command lines set up, and also to handle
-  // having some of the code live in chrome.exe, while having the database be
-  // accessed by browser code in chrome.dll (to get a list of uploaded crashes
-  // for chrome://crashes).
-  crash_reporter::InitializeCrashpad(process_type.empty(), process_type);
-#endif  // OS_WIN
-
-#if defined(OS_WIN)
   child_process_logging::Init();
 #endif
 #if defined(ARCH_CPU_ARM_FAMILY) && (defined(OS_ANDROID) || defined(OS_LINUX))
@@ -802,7 +796,11 @@
 #if defined(OS_ANDROID)
     if (process_type.empty()) {
       breakpad::InitCrashReporter(process_type);
+// TODO(crbug.com/551176): Exception reporting should work without
+// ANDROID_JAVA_UI
+#if BUILDFLAG(ANDROID_JAVA_UI)
       chrome::android::InitJavaExceptionReporter();
+#endif
     } else {
       breakpad::InitNonBrowserCrashReporterForAndroid(process_type);
     }
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index c9a811d..5ccdbe7 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -5832,12 +5832,6 @@
       <message name="IDS_FLAGS_GPU_RASTERIZATION_MSAA_SAMPLE_COUNT_SIXTEEN" desc="">
         16
       </message>
-      <message name="IDS_FLAGS_ENABLE_SLIMMING_PAINT_V2_NAME" desc="Title for the flag to enable slimming paint phase 2.">
-        Enable slimming paint phase 2.
-      </message>
-      <message name="IDS_FLAGS_ENABLE_SLIMMING_PAINT_V2_DESCRIPTION" desc="Description for the flag to enable slimming paint phase 2.">
-        Enable slimming paint phase 2 (display list based layerization, sub-tree painting optimization, etc.)
-      </message>
       <message name="IDS_FLAGS_EXPERIMENTAL_SECURITY_FEATURES_NAME" desc="Name for the flag to enable experimental security features.">
         Potentially annoying security features
       </message>
@@ -6508,6 +6502,14 @@
       <message name="IDS_FLAGS_WIFI_CREDENTIAL_SYNC_DESCRIPTION" desc="Decription for the flag to enable WiFi credential sync, a feature which enables synchronizing WiFi network settings across devices.">
         Enables synchronizing WiFi network settings across devices. When enabled, the WiFi credential datatype is registered with Chrome Sync, and WiFi credentials are synchronized subject to user preferences. (See also, chrome://settings/syncSetup.)
       </message>
+      <if expr="is_win">
+        <message name="IDS_FLAGS_WINDOWS_DESKTOP_SEARCH_REDIRECTION_DESCRIPTION" desc="Description for the flag to enable a preference that allows redirection of Windows desktop searches to the default search engine.">
+          Enables a preference that allows redirection of Windows desktop searches to the default search engine.
+        </message>
+        <message name="IDS_FLAGS_WINDOWS_DESKTOP_SEARCH_REDIRECTION_NAME" desc="Title for the flag to enable a preference that allows redirection of Windows desktop searches to the default search engine.">
+          Windows desktop search redirection preference
+        </message>
+      </if>
       <message name="IDS_FLAGS_SYNC_SANDBOX_NAME" desc="Name for the flag that causes Chrome to use the sandbox (testing) server for Sync.">
         Use Chrome Sync sandbox
       </message>
@@ -6673,6 +6675,18 @@
           Enables a new option to upload credit cards to Google Payments for sync to all Chrome devices.
         </message>
       </if>
+      <message name="IDS_FLAGS_FORCE_UI_DIRECTION_NAME" desc="Name for the flag to force a specific UI direction.">
+          Force UI direction
+      </message>
+      <message name="IDS_FLAGS_FORCE_UI_DIRECTION_DESCRIPTION" desc="Description for the flag to force a specific UI direction.">
+          Explicitly force the UI to left-to-right or right-to-left mode, overriding the default direction of the UI language.
+      </message>
+      <message name="IDS_FLAGS_FORCE_UI_DIRECTION_LTR" desc="Name for the option to force left-to-right UI direction mode.">
+          Left-to-right
+      </message>
+      <message name="IDS_FLAGS_FORCE_UI_DIRECTION_RTL" desc="Name for the option to force right-to-left UI direction mode.">
+          Right-to-left
+      </message>
 
       <!-- WebRTC logs -->
       <message name="IDS_WEBRTC_LOGS_TITLE" desc="Title for the chrome://webrtc-logs page.">
diff --git a/chrome/app/settings_strings.grdp b/chrome/app/settings_strings.grdp
index ce3f6bf87..905c1a3 100644
--- a/chrome/app/settings_strings.grdp
+++ b/chrome/app/settings_strings.grdp
@@ -564,6 +564,9 @@
   <message name="IDS_SETTINGS_SYNC_DISCONNECT_CONFIRM" desc="The text to display on the button to confirm the user wishes to stop syncing.">
     Clear and Disconnect
   </message>
+  <message name="IDS_SETTINGS_SYNC_MANAGE_OTHER_PEOPLE" desc="Label for the button that opens the multi profile user manager.">
+    Manage other people
+  </message>
 
   <message name="IDS_SETTINGS_SYNC" desc="Name of the settings page which manages syncing data between multiple browser instances with the same Google profile.">
     Advanced sync settings
@@ -574,12 +577,9 @@
   <message name="IDS_SETTINGS_SYNC_TIMEOUT" desc="Text explaining what to do if sync times out.">
     Please make sure your network connection is working and if the problem persists, please sign out and sign in again to refresh your credentials.
   </message>
-  <message name="IDS_SETTINGS_SYNC_EVERYTHING_MENU_OPTION" desc="Name of the menu option which, when selected, causes all properties to be synced.">
+  <message name="IDS_SETTINGS_SYNC_EVERYTHING_CHECKBOX_LABEL" desc="Label for the checkbox which causes all properties to be synced.">
     Sync everything
   </message>
-  <message name="IDS_SETTINGS_CHOOSE_WHAT_TO_SYNC_MENU_OPTION" desc="Name of the menu option which, when selected, allows the user to select a subset of properties to be synced.">
-    Choose what to sync
-  </message>
   <message name="IDS_SETTINGS_APPS_CHECKBOX_LABEL" desc="Label for the checkbox which enables or disables syncing apps between multiple browser instances.">
     Apps
   </message>
diff --git a/chrome/app/theme/default_100_percent/common/notification_tray_attention.png b/chrome/app/theme/default_100_percent/common/notification_tray_attention.png
deleted file mode 100644
index f7bff3bb..0000000
--- a/chrome/app/theme/default_100_percent/common/notification_tray_attention.png
+++ /dev/null
Binary files differ
diff --git a/chrome/app/theme/default_100_percent/common/notification_tray_do_not_disturb_attention.png b/chrome/app/theme/default_100_percent/common/notification_tray_do_not_disturb_attention.png
deleted file mode 100644
index 6b4a2c4..0000000
--- a/chrome/app/theme/default_100_percent/common/notification_tray_do_not_disturb_attention.png
+++ /dev/null
Binary files differ
diff --git a/chrome/app/theme/default_100_percent/common/notification_tray_do_not_disturb_empty.png b/chrome/app/theme/default_100_percent/common/notification_tray_do_not_disturb_empty.png
deleted file mode 100644
index c1e2bb0..0000000
--- a/chrome/app/theme/default_100_percent/common/notification_tray_do_not_disturb_empty.png
+++ /dev/null
Binary files differ
diff --git a/chrome/app/theme/default_100_percent/common/notification_tray_empty.png b/chrome/app/theme/default_100_percent/common/notification_tray_empty.png
deleted file mode 100644
index 65ff93d..0000000
--- a/chrome/app/theme/default_100_percent/common/notification_tray_empty.png
+++ /dev/null
Binary files differ
diff --git a/chrome/app/theme/default_100_percent/common/discard_wide.png b/chrome/app/theme/default_100_percent/cros/discard_wide.png
similarity index 100%
rename from chrome/app/theme/default_100_percent/common/discard_wide.png
rename to chrome/app/theme/default_100_percent/cros/discard_wide.png
Binary files differ
diff --git a/chrome/app/theme/default_100_percent/common/downloads/cancel.png b/chrome/app/theme/default_100_percent/cros/downloads/cancel.png
similarity index 100%
rename from chrome/app/theme/default_100_percent/common/downloads/cancel.png
rename to chrome/app/theme/default_100_percent/cros/downloads/cancel.png
Binary files differ
diff --git a/chrome/app/theme/default_100_percent/common/downloads/delete.png b/chrome/app/theme/default_100_percent/cros/downloads/delete.png
similarity index 100%
rename from chrome/app/theme/default_100_percent/common/downloads/delete.png
rename to chrome/app/theme/default_100_percent/cros/downloads/delete.png
Binary files differ
diff --git a/chrome/app/theme/default_100_percent/common/downloads/download.png b/chrome/app/theme/default_100_percent/cros/downloads/download.png
similarity index 100%
rename from chrome/app/theme/default_100_percent/common/downloads/download.png
rename to chrome/app/theme/default_100_percent/cros/downloads/download.png
Binary files differ
diff --git a/chrome/app/theme/default_100_percent/common/downloads/folder.png b/chrome/app/theme/default_100_percent/cros/downloads/folder.png
similarity index 100%
rename from chrome/app/theme/default_100_percent/common/downloads/folder.png
rename to chrome/app/theme/default_100_percent/cros/downloads/folder.png
Binary files differ
diff --git a/chrome/app/theme/default_100_percent/common/downloads/pause.png b/chrome/app/theme/default_100_percent/cros/downloads/pause.png
similarity index 100%
rename from chrome/app/theme/default_100_percent/common/downloads/pause.png
rename to chrome/app/theme/default_100_percent/cros/downloads/pause.png
Binary files differ
diff --git a/chrome/app/theme/default_100_percent/common/snapshot_wide.png b/chrome/app/theme/default_100_percent/cros/snapshot_wide.png
similarity index 100%
rename from chrome/app/theme/default_100_percent/common/snapshot_wide.png
rename to chrome/app/theme/default_100_percent/cros/snapshot_wide.png
Binary files differ
diff --git a/chrome/app/theme/default_200_percent/common/notification_tray_attention.png b/chrome/app/theme/default_200_percent/common/notification_tray_attention.png
deleted file mode 100644
index 13eec9b..0000000
--- a/chrome/app/theme/default_200_percent/common/notification_tray_attention.png
+++ /dev/null
Binary files differ
diff --git a/chrome/app/theme/default_200_percent/common/notification_tray_do_not_disturb_attention.png b/chrome/app/theme/default_200_percent/common/notification_tray_do_not_disturb_attention.png
deleted file mode 100644
index 6f81568..0000000
--- a/chrome/app/theme/default_200_percent/common/notification_tray_do_not_disturb_attention.png
+++ /dev/null
Binary files differ
diff --git a/chrome/app/theme/default_200_percent/common/notification_tray_do_not_disturb_empty.png b/chrome/app/theme/default_200_percent/common/notification_tray_do_not_disturb_empty.png
deleted file mode 100644
index 919cbd8..0000000
--- a/chrome/app/theme/default_200_percent/common/notification_tray_do_not_disturb_empty.png
+++ /dev/null
Binary files differ
diff --git a/chrome/app/theme/default_200_percent/common/notification_tray_empty.png b/chrome/app/theme/default_200_percent/common/notification_tray_empty.png
deleted file mode 100644
index fcaf932..0000000
--- a/chrome/app/theme/default_200_percent/common/notification_tray_empty.png
+++ /dev/null
Binary files differ
diff --git a/chrome/app/theme/default_200_percent/common/discard_wide.png b/chrome/app/theme/default_200_percent/cros/discard_wide.png
similarity index 100%
rename from chrome/app/theme/default_200_percent/common/discard_wide.png
rename to chrome/app/theme/default_200_percent/cros/discard_wide.png
Binary files differ
diff --git a/chrome/app/theme/default_200_percent/common/downloads/cancel.png b/chrome/app/theme/default_200_percent/cros/downloads/cancel.png
similarity index 100%
rename from chrome/app/theme/default_200_percent/common/downloads/cancel.png
rename to chrome/app/theme/default_200_percent/cros/downloads/cancel.png
Binary files differ
diff --git a/chrome/app/theme/default_200_percent/common/downloads/delete.png b/chrome/app/theme/default_200_percent/cros/downloads/delete.png
similarity index 100%
rename from chrome/app/theme/default_200_percent/common/downloads/delete.png
rename to chrome/app/theme/default_200_percent/cros/downloads/delete.png
Binary files differ
diff --git a/chrome/app/theme/default_200_percent/common/downloads/download.png b/chrome/app/theme/default_200_percent/cros/downloads/download.png
similarity index 100%
rename from chrome/app/theme/default_200_percent/common/downloads/download.png
rename to chrome/app/theme/default_200_percent/cros/downloads/download.png
Binary files differ
diff --git a/chrome/app/theme/default_200_percent/common/downloads/folder.png b/chrome/app/theme/default_200_percent/cros/downloads/folder.png
similarity index 100%
rename from chrome/app/theme/default_200_percent/common/downloads/folder.png
rename to chrome/app/theme/default_200_percent/cros/downloads/folder.png
Binary files differ
diff --git a/chrome/app/theme/default_200_percent/common/downloads/pause.png b/chrome/app/theme/default_200_percent/cros/downloads/pause.png
similarity index 100%
rename from chrome/app/theme/default_200_percent/common/downloads/pause.png
rename to chrome/app/theme/default_200_percent/cros/downloads/pause.png
Binary files differ
diff --git a/chrome/app/theme/default_200_percent/common/snapshot_wide.png b/chrome/app/theme/default_200_percent/cros/snapshot_wide.png
similarity index 100%
rename from chrome/app/theme/default_200_percent/common/snapshot_wide.png
rename to chrome/app/theme/default_200_percent/cros/snapshot_wide.png
Binary files differ
diff --git a/chrome/app/theme/theme_resources.grd b/chrome/app/theme/theme_resources.grd
index 261f3f4..77b7c33 100644
--- a/chrome/app/theme/theme_resources.grd
+++ b/chrome/app/theme/theme_resources.grd
@@ -247,11 +247,11 @@
       <structure type="chrome_scaled_image" name="IDR_DOWNLOAD_PROGRESS_BACKGROUND_32" file="common/download_progress_background32.png" />
       <structure type="chrome_scaled_image" name="IDR_DOWNLOAD_PROGRESS_FOREGROUND_32" file="common/download_progress_foreground32.png" />
       <if expr="chromeos">
-        <structure type="chrome_scaled_image" name="IDR_DOWNLOAD_NOTIFICATION_MENU_CANCEL" file="common/downloads/cancel.png" />
-        <structure type="chrome_scaled_image" name="IDR_DOWNLOAD_NOTIFICATION_MENU_DELETE" file="common/downloads/delete.png" />
-        <structure type="chrome_scaled_image" name="IDR_DOWNLOAD_NOTIFICATION_MENU_DOWNLOAD" file="common/downloads/download.png" />
-        <structure type="chrome_scaled_image" name="IDR_DOWNLOAD_NOTIFICATION_MENU_FOLDER" file="common/downloads/folder.png" />
-        <structure type="chrome_scaled_image" name="IDR_DOWNLOAD_NOTIFICATION_MENU_PAUSE" file="common/downloads/pause.png" />
+        <structure type="chrome_scaled_image" name="IDR_DOWNLOAD_NOTIFICATION_MENU_CANCEL" file="cros/downloads/cancel.png" />
+        <structure type="chrome_scaled_image" name="IDR_DOWNLOAD_NOTIFICATION_MENU_DELETE" file="cros/downloads/delete.png" />
+        <structure type="chrome_scaled_image" name="IDR_DOWNLOAD_NOTIFICATION_MENU_DOWNLOAD" file="cros/downloads/download.png" />
+        <structure type="chrome_scaled_image" name="IDR_DOWNLOAD_NOTIFICATION_MENU_FOLDER" file="cros/downloads/folder.png" />
+        <structure type="chrome_scaled_image" name="IDR_DOWNLOAD_NOTIFICATION_MENU_PAUSE" file="cros/downloads/pause.png" />
         <structure type="chrome_scaled_image" name="IDR_ENABLE_DEBUGGING_FAILURE" file="cros/enable_debugging_failure.png" />
         <structure type="chrome_scaled_image" name="IDR_ENABLE_DEBUGGING_SUCCESS" file="cros/enable_debugging_success.png" />
       </if>
@@ -421,8 +421,6 @@
         <!-- TODO(nkostylev): This resource needs to be removed when cros login code is moved to ash. -->
         <structure type="chrome_scaled_image" name="IDR_LAUNCHER_BACKGROUND" file="cros/launcher_background.png" />
         <structure type="chrome_scaled_image" name="IDR_LOGIN_PASSWORD_CAPS_LOCK" file="cros/login_password_capslock.png" />
-      </if>
-      <if expr="chromeos">
         <structure type="chrome_scaled_image" name="IDR_KIOSK_APP_USER_POD_ICON" file="cros/kiosk_app_user_pod_icon.png" />
         <structure type="chrome_scaled_image" name="IDR_LEGACY_SUPERVISED_USER_ICON" file="cros/limited_user.png" />
       </if>
@@ -442,8 +440,6 @@
       <structure type="chrome_scaled_image" name="IDR_MINIMIZE_BUTTON_MASK" file="common/minimize_button_mask.png" />
       <if expr="chromeos">
         <structure type="chrome_scaled_image" name="IDR_MIRROR_FLIP" file="cros/mirror_flip.png" />
-      </if>
-      <if expr="chromeos">
         <structure type="chrome_scaled_image" name="IDR_NETWORK_ADD_CONNECTION" file="cros/network_add_connection.png" />
         <structure type="chrome_scaled_image" name="IDR_NETWORK_HIDE_PASSWORD" file="cros/network_hide_password.png" />
         <structure type="chrome_scaled_image" name="IDR_NETWORK_HIDE_PASSWORD_HOVER" file="cros/network_hide_password_hover.png" />
@@ -471,12 +467,6 @@
         <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_PERIPHERAL_BATTERY_LOW" file="cros/notification_peripheral_battery_low.png" />
         <structure type="chrome_scaled_image" name="IDR_PORTAL_DETECTION_ALERT" file="cros/captive_portal_icon.png" />
       </if>
-      <if expr="is_win or desktop_linux">
-        <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_TRAY_DO_NOT_DISTURB_ATTENTION" file="common/notification_tray_do_not_disturb_attention.png" />
-        <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_TRAY_DO_NOT_DISTURB_EMPTY" file="common/notification_tray_do_not_disturb_empty.png" />
-        <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_TRAY_ATTENTION" file="common/notification_tray_attention.png" />
-        <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_TRAY_EMPTY" file="common/notification_tray_empty.png" />
-      </if>
       <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_WELCOME_ICON" file="common/notification_welcome_icon.png" />
       <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_WELCOME_LEARN_MORE" file="common/notification_welcome_learn_more.png" />
       <structure type="chrome_scaled_image" name="IDR_NOTIFIER_BLOCK_BUTTON" file="common/block_notifier.png" />
@@ -976,8 +966,8 @@
       <structure type="chrome_scaled_image" name="IDR_UPDATE_MENU_SEVERITY_HIGH" file="common/update_menu_severity_high.png" />
       <structure type="chrome_scaled_image" name="IDR_USB_NOTIFICATION_ICON" file="common/notification_usb_icon.png" />
       <if expr="chromeos">
-        <structure type="chrome_scaled_image" name="IDR_USER_IMAGE_CAPTURE" file="common/snapshot_wide.png" />
-        <structure type="chrome_scaled_image" name="IDR_USER_IMAGE_RECYCLE" file="common/discard_wide.png" />
+        <structure type="chrome_scaled_image" name="IDR_USER_IMAGE_CAPTURE" file="cros/snapshot_wide.png" />
+        <structure type="chrome_scaled_image" name="IDR_USER_IMAGE_RECYCLE" file="cros/discard_wide.png" />
       </if>
       <structure type="chrome_scaled_image" name="IDR_WARNING" file="common/alert_small.png" />
       <if expr="is_macosx">
@@ -1010,12 +1000,14 @@
       </if>
 
       <!-- People search images -->
-      <structure type="chrome_scaled_image" name="IDR_PEOPLE_SEARCH_ACTION_EMAIL" file="common/mail.png" />
-      <structure type="chrome_scaled_image" name="IDR_PEOPLE_SEARCH_ACTION_EMAIL_HOVER" file="common/mail_hover.png" />
-      <structure type="chrome_scaled_image" name="IDR_PEOPLE_SEARCH_ACTION_EMAIL_PRESSED" file="common/mail_pressed.png" />
-      <structure type="chrome_scaled_image" name="IDR_PEOPLE_SEARCH_ACTION_CHAT" file="common/chat.png" />
-      <structure type="chrome_scaled_image" name="IDR_PEOPLE_SEARCH_ACTION_CHAT_HOVER" file="common/chat_hover.png" />
-      <structure type="chrome_scaled_image" name="IDR_PEOPLE_SEARCH_ACTION_CHAT_PRESSED" file="common/chat_pressed.png" />
+      <if expr="enable_app_list">
+        <structure type="chrome_scaled_image" name="IDR_PEOPLE_SEARCH_ACTION_EMAIL" file="common/mail.png" />
+        <structure type="chrome_scaled_image" name="IDR_PEOPLE_SEARCH_ACTION_EMAIL_HOVER" file="common/mail_hover.png" />
+        <structure type="chrome_scaled_image" name="IDR_PEOPLE_SEARCH_ACTION_EMAIL_PRESSED" file="common/mail_pressed.png" />
+        <structure type="chrome_scaled_image" name="IDR_PEOPLE_SEARCH_ACTION_CHAT" file="common/chat.png" />
+        <structure type="chrome_scaled_image" name="IDR_PEOPLE_SEARCH_ACTION_CHAT_HOVER" file="common/chat_hover.png" />
+        <structure type="chrome_scaled_image" name="IDR_PEOPLE_SEARCH_ACTION_CHAT_PRESSED" file="common/chat_pressed.png" />
+      </if>
     </structures>
   </release>
 </grit>
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 22dc1a5..1a4b876 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -276,6 +276,34 @@
     sources += rebase_path(gypi_values.chrome_browser_web_resource_sources,
                            ".",
                            "//chrome")
+    if (android_java_ui) {
+      sources +=
+          rebase_path(gypi_values.chrome_browser_sync_android_java_ui_sources,
+                      ".",
+                      "//chrome")
+      sources +=
+          rebase_path(gypi_values.chrome_browser_ssl_android_java_ui_sources,
+                      ".",
+                      "//chrome")
+      sources += rebase_path(
+              gypi_values.chrome_browser_history_android_java_ui_sources,
+              ".",
+              "//chrome")
+      sources += rebase_path(
+              gypi_values.chrome_browser_permissions_android_java_ui_sources,
+              ".",
+              "//chrome")
+      sources += rebase_path(
+              gypi_values.chrome_browser_search_engines_android_java_ui_sources,
+              ".",
+              "//chrome")
+      if (enable_supervised_users) {
+        sources += rebase_path(
+                gypi_values.chrome_browser_supervised_user_android_java_ui_sources,
+                ".",
+                "//chrome")
+      }
+    }
 
     deps += [
       "//apps",
@@ -358,13 +386,6 @@
     if (toolkit_views) {
       deps += [ "//ui/views" ]
     }
-
-    if (is_android && use_aura) {
-      sources -= [
-        # Aura Android uses platform_util_aura implementation.
-        "platform_util_android.cc",
-      ]
-    }
   } else {  # iOS
     sources +=
         rebase_path(gypi_values.chrome_browser_ios_sources, ".", "//chrome")
@@ -622,7 +643,7 @@
   } else {
     sources -= [ "password_manager/password_store_x.cc" ]
   }
-  if ((is_posix && !is_mac && !is_ios) || is_win) {
+  if (is_posix && !is_mac && !is_ios) {
     sources += [
       "//chrome/app/chrome_crash_reporter_client.cc",
       "//chrome/app/chrome_crash_reporter_client.h",
@@ -644,11 +665,11 @@
     sources += rebase_path(gypi_values.chrome_browser_notifications_sources,
                            ".",
                            "//chrome")
-    if (is_android) {
-      sources +=
-          rebase_path(gypi_values.chrome_browser_notifications_android_sources,
-                      ".",
-                      "//chrome")
+    if (android_java_ui) {
+      sources += rebase_path(
+              gypi_values.chrome_browser_notifications_android_java_ui_sources,
+              ".",
+              "//chrome")
     } else {
       sources += rebase_path(
               gypi_values.chrome_browser_notifications_non_android_sources,
@@ -727,6 +748,12 @@
   if (is_android) {
     sources +=
         rebase_path(gypi_values.chrome_browser_android_sources, ".", "//chrome")
+  }
+
+  if (android_java_ui) {
+    sources += rebase_path(gypi_values.chrome_browser_android_java_ui_sources,
+                           ".",
+                           "//chrome")
     sources += rebase_path(gypi_values.chrome_browser_bookmark_android_sources,
                            ".",
                            "//chrome")
@@ -734,7 +761,6 @@
       ":client_discourse_context_proto",
       ":delta_file_proto",
       ":jni_headers",
-      "//components/cdm/browser",
       "//components/data_usage/android",
       "//components/enhanced_bookmarks",
       "//components/precache/content",
@@ -743,16 +769,25 @@
       "//components/service_tab_launcher",
       "//components/toolbar",
       "//components/web_contents_delegate_android",
+    ]
+
+    defines += [ "ENABLE_DATA_REDUCTION_PROXY_DEBUGGING" ]
+  }
+
+  if (is_android) {
+    deps += [
+      "//components/cdm/browser",
+      "//components/resources:components_resources",
       "//third_party/android_opengl/etc1",
       "//third_party/android_tools:cpu_features",
       "//third_party/libaddressinput:util",
     ]
+
     deps -= [
       "//components/storage_monitor",
       "//components/web_modal",
       "//third_party/libaddressinput",
     ]
-    defines += [ "ENABLE_DATA_REDUCTION_PROXY_DEBUGGING" ]
 
     if (use_seccomp_bpf) {
       defines += [ "USE_SECCOMP_BPF" ]
@@ -924,7 +959,7 @@
   }
 }
 
-if (is_android) {
+if (android_java_ui) {
   # GYP version: chrome/chrome_browser.gypi:chrome_browser_jni_headers
   generate_jni("jni_headers") {
     sources =
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index bdd2f74..62afd84a 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -13,6 +13,7 @@
 #include "base/callback.h"
 #include "base/command_line.h"
 #include "base/feature_list.h"
+#include "base/i18n/base_i18n_switches.h"
 #include "base/memory/singleton.h"
 #include "base/metrics/metrics_hashes.h"
 #include "base/metrics/sparse_histogram.h"
@@ -67,15 +68,15 @@
 #include "ui/message_center/message_center_switches.h"
 #endif
 
-#if defined(USE_ASH)
-#include "ash/ash_switches.h"
-#endif
-
 #if defined(OS_CHROMEOS)
 #include "chromeos/chromeos_switches.h"
 #include "third_party/cros_system_api/switches/chrome_switches.h"
 #endif
 
+#if defined(OS_WIN)
+#include "components/search_engines/desktop_search_win.h"
+#endif  // defined(OS_WIN)
+
 #if defined(ENABLE_APP_LIST)
 #include "ui/app_list/app_list_switches.h"
 #endif
@@ -88,6 +89,10 @@
 #include "chrome/browser/ui/webui/print_preview/print_preview_distiller.h"
 #endif
 
+#if defined(USE_ASH)
+#include "ash/ash_switches.h"
+#endif
+
 #if defined(USE_OZONE)
 #include "ui/ozone/public/ozone_switches.h"
 #endif
@@ -509,6 +514,14 @@
 };
 #endif  // defined(OS_WIN)
 
+const FeatureEntry::Choice kForceUIDirectionChoices[] = {
+    {IDS_GENERIC_EXPERIMENT_CHOICE_DEFAULT, "", ""},
+    {IDS_FLAGS_FORCE_UI_DIRECTION_LTR, switches::kForceUIDirection,
+     switches::kForceUIDirectionLTR},
+    {IDS_FLAGS_FORCE_UI_DIRECTION_RTL, switches::kForceUIDirection,
+     switches::kForceUIDirectionRTL},
+};
+
 // RECORDING USER METRICS FOR FLAGS:
 // -----------------------------------------------------------------------------
 // The first line of the entry is the internal name. If you'd like to gather
@@ -754,11 +767,6 @@
      IDS_FLAGS_GPU_RASTERIZATION_MSAA_SAMPLE_COUNT_DESCRIPTION,
      kOsAll,
      MULTI_VALUE_TYPE(kGpuRasterizationMSAASampleCountChoices)},
-     {"enable-slimming-paint-v2",
-      IDS_FLAGS_ENABLE_SLIMMING_PAINT_V2_NAME,
-      IDS_FLAGS_ENABLE_SLIMMING_PAINT_V2_DESCRIPTION,
-      kOsAll,
-      SINGLE_VALUE_TYPE(switches::kEnableSlimmingPaintV2)},
     {"enable-experimental-web-platform-features",
      IDS_FLAGS_EXPERIMENTAL_WEB_PLATFORM_FEATURES_NAME,
      IDS_FLAGS_EXPERIMENTAL_WEB_PLATFORM_FEATURES_DESCRIPTION,
@@ -2078,6 +2086,18 @@
       IDS_FLAGS_ENABLE_MATERIAL_DESIGN_HISTORY_DESCRIPTION,
       kOsDesktop | kOsAndroid,
       SINGLE_VALUE_TYPE(switches::kEnableMaterialDesignHistory)},
+#if defined(OS_WIN)
+    {"enable-windows-desktop-search-redirection",
+     IDS_FLAGS_WINDOWS_DESKTOP_SEARCH_REDIRECTION_NAME,
+     IDS_FLAGS_WINDOWS_DESKTOP_SEARCH_REDIRECTION_DESCRIPTION,
+     kOsWin,
+     FEATURE_VALUE_TYPE(kWindowsDesktopSearchRedirectionFeature)},
+#endif  // defined(OS_WIN)
+    {"force-ui-direction",
+     IDS_FLAGS_FORCE_UI_DIRECTION_NAME,
+     IDS_FLAGS_FORCE_UI_DIRECTION_DESCRIPTION,
+     kOsAll,
+     MULTI_VALUE_TYPE(kForceUIDirectionChoices)},
     // NOTE: Adding new command-line switches requires adding corresponding
     // entries to enum "LoginCustomFlags" in histograms.xml. See note in
     // histograms.xml and don't forget to run AboutFlagsHistogramTest unit test.
diff --git a/chrome/browser/android/compositor/scene_layer/static_tab_scene_layer.cc b/chrome/browser/android/compositor/scene_layer/static_tab_scene_layer.cc
index 26d7e8a..715d9c6a 100644
--- a/chrome/browser/android/compositor/scene_layer/static_tab_scene_layer.cc
+++ b/chrome/browser/android/compositor/scene_layer/static_tab_scene_layer.cc
@@ -127,14 +127,24 @@
     const JavaParamRef<jobject>& jobj,
     const JavaParamRef<jobject>& jcontent_scene_layer) {
   SceneLayer* content_scene_layer = FromJavaObject(env, jcontent_scene_layer);
-  if (content_scene_layer && content_scene_layer->layer()) {
-    content_scene_layer_ = content_scene_layer->layer();
-    if (content_scene_layer_.get())
-      layer_->AddChild(content_scene_layer_);
-  } else if (content_scene_layer_) {
+  scoped_refptr<cc::Layer> layer = content_scene_layer ?
+      content_scene_layer->layer() : nullptr;
+
+  if (content_scene_layer_ && content_scene_layer_ != layer) {
     content_scene_layer_->RemoveFromParent();
     content_scene_layer_ = nullptr;
   }
+
+  // TODO(pedrosimonetti): Consider being smarter with regards to when to
+  // add the layer to the hierarchy. For now, we need to keep adding the
+  // content_scene_layer on every frame because the content_layer is also
+  // added on every frame. This means that if we only add it once, the
+  // content_layer will be added again on the next frame and will
+  // occlude the content_scene_layer.
+  if (layer) {
+    content_scene_layer_ = layer;
+    layer_->AddChild(layer);
+  }
 }
 
 static jlong Init(JNIEnv* env, const JavaParamRef<jobject>& jobj) {
diff --git a/chrome/browser/android/most_visited_sites.cc b/chrome/browser/android/most_visited_sites.cc
index 15bc063..c3001eb3 100644
--- a/chrome/browser/android/most_visited_sites.cc
+++ b/chrome/browser/android/most_visited_sites.cc
@@ -82,12 +82,6 @@
     ICON_COLOR,
     // The item displays a default gray box in place of an icon.
     ICON_DEFAULT,
-    // The item displays a locally-captured thumbnail of the site content.
-    THUMBNAIL_LOCAL,
-    // The item displays a server-provided thumbnail of the site content.
-    THUMBNAIL_SERVER,
-    // The item displays a default graphic in place of a thumbnail.
-    THUMBNAIL_DEFAULT,
     NUM_TILE_TYPES,
 };
 
@@ -379,8 +373,7 @@
 void MostVisitedSites::RecordTileTypeMetrics(
     JNIEnv* env,
     const JavaParamRef<jobject>& obj,
-    const JavaParamRef<jintArray>& jtile_types,
-    jboolean is_icon_mode) {
+    const JavaParamRef<jintArray>& jtile_types) {
   std::vector<int> tile_types;
   base::android::JavaIntArrayToIntVector(env, jtile_types, &tile_types);
   DCHECK_EQ(current_suggestions_.size(), tile_types.size());
@@ -395,21 +388,12 @@
     LogHistogramEvent(histogram, tile_type, NUM_TILE_TYPES);
   }
 
-  if (is_icon_mode) {
-    UMA_HISTOGRAM_SPARSE_SLOWLY("NewTabPage.IconsReal",
-                                counts_per_type[ICON_REAL]);
-    UMA_HISTOGRAM_SPARSE_SLOWLY("NewTabPage.IconsColor",
-                                counts_per_type[ICON_COLOR]);
-    UMA_HISTOGRAM_SPARSE_SLOWLY("NewTabPage.IconsGray",
-                                counts_per_type[ICON_DEFAULT]);
-  } else {
-    UMA_HISTOGRAM_SPARSE_SLOWLY("NewTabPage.NumberOfThumbnailTiles",
-                                counts_per_type[THUMBNAIL_LOCAL]);
-    UMA_HISTOGRAM_SPARSE_SLOWLY("NewTabPage.NumberOfExternalTiles",
-                                counts_per_type[THUMBNAIL_SERVER]);
-    UMA_HISTOGRAM_SPARSE_SLOWLY("NewTabPage.NumberOfGrayTiles",
-                                counts_per_type[THUMBNAIL_DEFAULT]);
-  }
+  UMA_HISTOGRAM_SPARSE_SLOWLY("NewTabPage.IconsReal",
+                              counts_per_type[ICON_REAL]);
+  UMA_HISTOGRAM_SPARSE_SLOWLY("NewTabPage.IconsColor",
+                              counts_per_type[ICON_COLOR]);
+  UMA_HISTOGRAM_SPARSE_SLOWLY("NewTabPage.IconsGray",
+                              counts_per_type[ICON_DEFAULT]);
 }
 
 void MostVisitedSites::RecordOpenedMostVisitedItem(
diff --git a/chrome/browser/android/most_visited_sites.h b/chrome/browser/android/most_visited_sites.h
index 9a0bb35..b921d21 100644
--- a/chrome/browser/android/most_visited_sites.h
+++ b/chrome/browser/android/most_visited_sites.h
@@ -54,8 +54,7 @@
   void RecordTileTypeMetrics(
       JNIEnv* env,
       const base::android::JavaParamRef<jobject>& obj,
-      const base::android::JavaParamRef<jintArray>& jtile_types,
-      jboolean is_icon_mode);
+      const base::android::JavaParamRef<jintArray>& jtile_types);
   void RecordOpenedMostVisitedItem(
       JNIEnv* env,
       const base::android::JavaParamRef<jobject>& obj,
diff --git a/chrome/browser/apps/guest_view/web_view_browsertest.cc b/chrome/browser/apps/guest_view/web_view_browsertest.cc
index 337b21f..1cb92bd9 100644
--- a/chrome/browser/apps/guest_view/web_view_browsertest.cc
+++ b/chrome/browser/apps/guest_view/web_view_browsertest.cc
@@ -1076,6 +1076,14 @@
              NO_TEST_SERVER);
 }
 
+IN_PROC_BROWSER_TEST_F(
+    WebViewTest,
+    Shim_TestExecuteScriptIsAbortedWhenWebViewSourceIsInvalid) {
+  TestHelper("testExecuteScriptIsAbortedWhenWebViewSourceIsInvalid",
+             "web_view/shim",
+             NO_TEST_SERVER);
+}
+
 IN_PROC_BROWSER_TEST_F(WebViewTest, Shim_TestTerminateAfterExit) {
   TestHelper("testTerminateAfterExit", "web_view/shim", NO_TEST_SERVER);
 }
diff --git a/chrome/browser/autofill/autofill_interactive_uitest.cc b/chrome/browser/autofill/autofill_interactive_uitest.cc
index c8b9980..51f13be 100644
--- a/chrome/browser/autofill/autofill_interactive_uitest.cc
+++ b/chrome/browser/autofill/autofill_interactive_uitest.cc
@@ -52,6 +52,7 @@
 #include "net/url_request/url_request_status.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/clipboard/scoped_clipboard_writer.h"
 #include "ui/events/keycodes/keyboard_codes.h"
 
 using base::ASCIIToUTF16;
@@ -89,14 +90,26 @@
     "<label for=\"phone\">Phone number:</label>"
     " <input type=\"text\" id=\"phone\"><br>"
     "</form>";
-
+static const char kTestPasswordFormString[] =
+    "<form>"
+    "<label for=\"user\">User:</label>"
+    " <input id=\"user\" type=\"text\" name=\"name\""
+             "onfocus=\"domAutomationController.send(true)\">"
+    "<br>"
+    "<label for=\"password\">Password:</label>"
+    " <input id=\"password\" type=\"password\" name=\"password\""
+             "onfocus=\"domAutomationController.send(true)\">"
+    "<br>"
+    "<input type=\"submit\" value=\"Submit\">"
+    "</form>";
 
 // AutofillManagerTestDelegateImpl --------------------------------------------
 
 class AutofillManagerTestDelegateImpl
     : public autofill::AutofillManagerTestDelegate {
  public:
-  AutofillManagerTestDelegateImpl() {}
+  AutofillManagerTestDelegateImpl()
+      : waiting_for_text_change_(false) {}
   ~AutofillManagerTestDelegateImpl() override {}
 
   // autofill::AutofillManagerTestDelegate:
@@ -115,6 +128,14 @@
     loop_runner_->Quit();
   }
 
+  void OnTextFieldChanged() override {
+    if (!waiting_for_text_change_)
+      return;
+    waiting_for_text_change_ = false;
+    ASSERT_TRUE(loop_runner_->loop_running());
+    loop_runner_->Quit();
+  }
+
   void Reset() {
     loop_runner_ = new content::MessageLoopRunner();
   }
@@ -123,8 +144,14 @@
     loop_runner_->Run();
   }
 
+  void WaitForTextChange() {
+    waiting_for_text_change_ = true;
+    loop_runner_->Run();
+  }
+
  private:
   scoped_refptr<content::MessageLoopRunner> loop_runner_;
+  bool waiting_for_text_change_;
 
   DISALLOW_COPY_AND_ASSIGN(AutofillManagerTestDelegateImpl);
 };
@@ -263,6 +290,18 @@
     fetcher->delegate()->OnURLFetchComplete(fetcher);
   }
 
+  void FocusFieldByName(const std::string& name) {
+    bool result = false;
+    ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
+        GetRenderViewHost(),
+        "if (document.readyState === 'complete')"
+        "  document.getElementById('" + name + "').focus();"
+        "else"
+        "  domAutomationController.send(false);",
+        &result));
+    ASSERT_TRUE(result);
+  }
+
   void FocusFirstNameField() {
     bool result = false;
     ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
@@ -333,6 +372,16 @@
     test_delegate_.Wait();
   }
 
+  void PasteStringAndWait(const std::string& pastedata) {
+    {
+      ui::ScopedClipboardWriter writer(ui::CLIPBOARD_TYPE_COPY_PASTE);
+      writer.WriteText(base::ASCIIToUTF16(pastedata));
+    }
+    test_delegate_.Reset();
+    GetWebContents()->Paste();
+    test_delegate_.WaitForTextChange();
+  }
+
   bool HandleKeyPressEvent(const content::NativeWebKeyboardEvent& event) {
     return true;
   }
@@ -1396,4 +1445,15 @@
   SendKeyToPopupAndWait(ui::VKEY_DOWN);
 }
 
+IN_PROC_BROWSER_TEST_F(AutofillInteractiveTest,
+                       PastedPasswordIsSaved) {
+  ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(browser(),
+      GURL(std::string(kDataURIPrefix) + kTestPasswordFormString)));
+  ASSERT_TRUE(content::ExecuteScript(
+      GetRenderViewHost(),
+      "document.getElementById('user').value = 'user';"));
+  FocusFieldByName("password");
+  PasteStringAndWait("foobar");
+}
+
 }  // namespace autofill
diff --git a/chrome/browser/background_sync/background_sync_controller_impl.cc b/chrome/browser/background_sync/background_sync_controller_impl.cc
index 895f8aeb..3c9238b7 100644
--- a/chrome/browser/background_sync/background_sync_controller_impl.cc
+++ b/chrome/browser/background_sync/background_sync_controller_impl.cc
@@ -6,9 +6,10 @@
 
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/common/features.h"
 #include "components/rappor/rappor_utils.h"
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
 #include "chrome/browser/android/background_sync_launcher_android.h"
 #endif
 
@@ -39,7 +40,7 @@
 
   if (profile_->IsOffTheRecord())
     return;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
   BackgroundSyncLauncherAndroid::LaunchBrowserIfStopped(enabled, min_ms);
 #else
 // TODO(jkarlin): Use BackgroundModeManager to enter background mode. See
diff --git a/chrome/browser/banners/app_banner_data_fetcher.cc b/chrome/browser/banners/app_banner_data_fetcher.cc
index 0090d10..321e8d3e 100644
--- a/chrome/browser/banners/app_banner_data_fetcher.cc
+++ b/chrome/browser/banners/app_banner_data_fetcher.cc
@@ -188,6 +188,9 @@
     return;
   }
 
+  AppBannerSettingsHelper::RecordMinutesFromFirstVisitToShow(
+      web_contents, validated_url_, GetAppIdentifier(), GetCurrentTime());
+
   // Definitely going to show the banner now.
   FOR_EACH_OBSERVER(Observer, observer_list_,
                     OnDecidedWhetherToShow(this, true));
diff --git a/chrome/browser/banners/app_banner_data_fetcher_browsertest.cc b/chrome/browser/banners/app_banner_data_fetcher_browsertest.cc
index b37df5f..c868268 100644
--- a/chrome/browser/banners/app_banner_data_fetcher_browsertest.cc
+++ b/chrome/browser/banners/app_banner_data_fetcher_browsertest.cc
@@ -9,8 +9,10 @@
 #include "base/run_loop.h"
 #include "base/single_thread_task_runner.h"
 #include "base/task_runner.h"
+#include "base/test/histogram_tester.h"
 #include "base/thread_task_runner_handle.h"
 #include "chrome/browser/banners/app_banner_data_fetcher_desktop.h"
+#include "chrome/browser/banners/app_banner_metrics.h"
 #include "chrome/browser/banners/app_banner_settings_helper.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
@@ -97,6 +99,7 @@
                                         weak_factory_.GetWeakPtr(),
                                         128, 128));
 
+    base::HistogramTester histograms;
     base::RunLoop run_loop;
     quit_closure_ = run_loop.QuitClosure();
     scoped_ptr<TestObserver> observer(new TestObserver(fetcher.get(),
@@ -107,6 +110,10 @@
     EXPECT_EQ(expected_non_web_platform, non_web_platform_);
     EXPECT_EQ(expected_to_show, observer->will_show());
     ASSERT_FALSE(fetcher->is_active());
+
+    // If showing the banner, ensure that the minutes histogram is recorded.
+    histograms.ExpectTotalCount(banners::kMinutesHistogram,
+                                (observer->will_show() ? 1 : 0));
   }
 
   void RunBannerTest(const std::string& manifest_page,
diff --git a/chrome/browser/banners/app_banner_metrics.cc b/chrome/browser/banners/app_banner_metrics.cc
index 5ab6f59a..f9bbd34 100644
--- a/chrome/browser/banners/app_banner_metrics.cc
+++ b/chrome/browser/banners/app_banner_metrics.cc
@@ -4,32 +4,48 @@
 
 #include "chrome/browser/banners/app_banner_metrics.h"
 
+#include "base/metrics/histogram_macros.h"
 #include "base/metrics/sparse_histogram.h"
 
 namespace banners {
 
+const char kDismissEventHistogram[] = "AppBanners.DismissEvent";
+const char kDisplayEventHistogram[] = "AppBanners.DisplayEvent";
+const char kInstallEventHistogram[] = "AppBanners.InstallEvent";
+const char kMinutesHistogram[] =
+    "AppBanners.MinutesFromFirstVisitToBannerShown";
+const char kUserResponseHistogram[] = "AppBanners.UserResponse";
+
 void TrackDismissEvent(int event) {
   DCHECK_LT(DISMISS_EVENT_MIN, event);
   DCHECK_LT(event, DISMISS_EVENT_MAX);
-  UMA_HISTOGRAM_SPARSE_SLOWLY("AppBanners.DismissEvent", event);
+  UMA_HISTOGRAM_SPARSE_SLOWLY(kDismissEventHistogram, event);
 }
 
 void TrackDisplayEvent(int event) {
   DCHECK_LT(DISPLAY_EVENT_MIN, event);
   DCHECK_LT(event, DISPLAY_EVENT_MAX);
-  UMA_HISTOGRAM_SPARSE_SLOWLY("AppBanners.DisplayEvent", event);
+  UMA_HISTOGRAM_SPARSE_SLOWLY(kDisplayEventHistogram, event);
 }
 
 void TrackInstallEvent(int event) {
   DCHECK_LT(INSTALL_EVENT_MIN, event);
   DCHECK_LT(event, INSTALL_EVENT_MAX);
-  UMA_HISTOGRAM_SPARSE_SLOWLY("AppBanners.InstallEvent", event);
+  UMA_HISTOGRAM_SPARSE_SLOWLY(kInstallEventHistogram, event);
+}
+
+void TrackMinutesFromFirstVisitToBannerShown(int minutes) {
+  // Histogram ranges from 1 minute to the number of minutes in 21 days.
+  // This is one more day than the decay length of time for site engagement,
+  // and seven more days than the expiry of visits for the app banner
+  // navigation heuristic.
+  UMA_HISTOGRAM_CUSTOM_COUNTS(kMinutesHistogram, minutes, 1, 30240, 100);
 }
 
 void TrackUserResponse(int event) {
   DCHECK_LT(USER_RESPONSE_MIN, event);
   DCHECK_LT(event, USER_RESPONSE_MAX);
-  UMA_HISTOGRAM_SPARSE_SLOWLY("AppBanners.UserResponse", event);
+  UMA_HISTOGRAM_SPARSE_SLOWLY(kUserResponseHistogram, event);
 }
 
 }  // namespace banners
diff --git a/chrome/browser/banners/app_banner_metrics.h b/chrome/browser/banners/app_banner_metrics.h
index 7c781792..0b0939ee 100644
--- a/chrome/browser/banners/app_banner_metrics.h
+++ b/chrome/browser/banners/app_banner_metrics.h
@@ -57,9 +57,16 @@
   USER_RESPONSE_MAX = 7,
 };
 
+extern const char kDismissEventHistogram[];
+extern const char kDisplayEventHistogram[];
+extern const char kInstallEventHistogram[];
+extern const char kMinutesHistogram[];
+extern const char kUserResponseHistogram[];
+
 void TrackDismissEvent(int event);
 void TrackDisplayEvent(int event);
 void TrackInstallEvent(int event);
+void TrackMinutesFromFirstVisitToBannerShown(int minutes);
 void TrackUserResponse(int event);
 
 };  // namespace banners
diff --git a/chrome/browser/banners/app_banner_settings_helper.cc b/chrome/browser/banners/app_banner_settings_helper.cc
index 2f0bb43..aca24f6 100644
--- a/chrome/browser/banners/app_banner_settings_helper.cc
+++ b/chrome/browser/banners/app_banner_settings_helper.cc
@@ -8,11 +8,14 @@
 #include <string>
 
 #include "base/command_line.h"
+#include "base/metrics/field_trial.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
 #include "chrome/browser/banners/app_banner_data_fetcher.h"
 #include "chrome/browser/banners/app_banner_metrics.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
+#include "chrome/browser/engagement/site_engagement_service.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/chrome_switches.h"
 #include "components/content_settings/core/browser/host_content_settings_map.h"
@@ -63,9 +66,11 @@
 const char kBannerParamsIndirectKey[] = "indirect";
 const char kBannerParamsTotalKey[] = "total";
 const char kBannerParamsMinutesKey[] = "minutes";
+const char kBannerSiteEngagementParamsKey[] = "app_banner_triggering";
+const char kBannerSiteEngagementParamsTotalKey[] =
+    "app_banner_triggering_total";
 
-// Total site engagements where a banner could have been shown before
-// a banner will actually be triggered.
+// Total engagement score required before a banner will actually be triggered.
 double gTotalEngagementToTrigger = 2;
 
 // Engagement weight assigned to direct and indirect navigations.
@@ -115,10 +120,26 @@
   }
 }
 
+// Queries variations for the maximum site engagement score required to trigger
+// the banner showing.
+void UpdateSiteEngagementToTrigger() {
+  std::string total_param = variations::GetVariationParamValue(
+      SiteEngagementService::kEngagementParams,
+      kBannerSiteEngagementParamsTotalKey);
+
+  if (!total_param.empty()) {
+    double total_engagement = -1;
+
+    if (base::StringToDouble(total_param, &total_engagement) &&
+        total_engagement > 0) {
+      AppBannerSettingsHelper::SetTotalEngagementToTrigger(total_engagement);
+    }
+  }
+}
+
 // Queries variations for updates to the default engagement values assigned
 // to direct and indirect navigations.
 void UpdateEngagementWeights() {
-  std::map<std::string, std::string> params;
   std::string direct_param = variations::GetVariationParamValue(
       kBannerParamsKey, kBannerParamsDirectKey);
   std::string indirect_param = variations::GetVariationParamValue(
@@ -160,6 +181,16 @@
   }
 }
 
+// Returns the site engagement karma score for the given origin URL under the
+// current profile.
+double GetSiteEngagementScoreForOrigin(
+    content::WebContents* web_contents,
+    const GURL& origin_url) {
+  SiteEngagementService* service = SiteEngagementService::Get(
+      Profile::FromBrowserContext(web_contents->GetBrowserContext()));
+  return service ? service->GetScore(origin_url) : 0;
+}
+
 }  // namespace
 
 void AppBannerSettingsHelper::ClearHistoryForURLs(
@@ -352,6 +383,10 @@
     return true;
   }
 
+  // Never show a banner when the package name or URL is empty.
+  if (package_name_or_start_url.empty())
+    return false;
+
   // Don't show if it has been added to the homescreen.
   base::Time added_time =
       GetSingleBannerEvent(web_contents, origin_url, package_name_or_start_url,
@@ -382,14 +417,17 @@
     return false;
   }
 
-  std::vector<BannerEvent> could_show_events = GetCouldShowBannerEvents(
-      web_contents, origin_url, package_name_or_start_url);
-
-  // Return true if the total engagement of each applicable could show event
-  // meets the trigger threshold.
   double total_engagement = 0;
-  for (const auto& event : could_show_events)
-    total_engagement += event.engagement;
+  if (ShouldUseSiteEngagementScore()) {
+    total_engagement =
+        GetSiteEngagementScoreForOrigin(web_contents, origin_url);
+  } else {
+    std::vector<BannerEvent> could_show_events = GetCouldShowBannerEvents(
+        web_contents, origin_url, package_name_or_start_url);
+
+    for (const auto& event : could_show_events)
+      total_engagement += event.engagement;
+  }
 
   if (total_engagement < gTotalEngagementToTrigger) {
     banners::TrackDisplayEvent(banners::DISPLAY_EVENT_NOT_VISITED_ENOUGH);
@@ -405,8 +443,6 @@
     const GURL& origin_url,
     const std::string& package_name_or_start_url) {
   std::vector<BannerEvent> result;
-  if (package_name_or_start_url.empty())
-    return result;
 
   Profile* profile =
       Profile::FromBrowserContext(web_contents->GetBrowserContext());
@@ -454,9 +490,6 @@
   DCHECK(event != APP_BANNER_EVENT_COULD_SHOW);
   DCHECK(event < APP_BANNER_EVENT_NUM_EVENTS);
 
-  if (package_name_or_start_url.empty())
-    return base::Time();
-
   Profile* profile =
       Profile::FromBrowserContext(web_contents->GetBrowserContext());
   HostContentSettingsMap* settings =
@@ -480,6 +513,21 @@
   return base::Time::FromInternalValue(internal_time);
 }
 
+void AppBannerSettingsHelper::RecordMinutesFromFirstVisitToShow(
+    content::WebContents* web_contents,
+    const GURL& origin_url,
+    const std::string& package_name_or_start_url,
+    base::Time time) {
+  std::vector<BannerEvent> could_show_events = GetCouldShowBannerEvents(
+      web_contents, origin_url, package_name_or_start_url);
+
+  int minutes = 0;
+  if (could_show_events.size())
+    minutes = (time - could_show_events[0].time).InMinutes();
+
+  banners::TrackMinutesFromFirstVisitToBannerShown(minutes);
+}
+
 void AppBannerSettingsHelper::SetEngagementWeights(double direct_engagement,
                                                    double indirect_engagement) {
   gDirectNavigationEngagement = direct_engagement;
@@ -523,6 +571,32 @@
 }
 
 void AppBannerSettingsHelper::UpdateFromFieldTrial() {
-  UpdateEngagementWeights();
-  UpdateMinutesBetweenVisits();
+  // If we are using the site engagement score, only extract the total
+  // engagement to trigger from the params variations.
+  if (ShouldUseSiteEngagementScore()) {
+    UpdateSiteEngagementToTrigger();
+  } else {
+    UpdateEngagementWeights();
+    UpdateMinutesBetweenVisits();
+  }
+}
+
+bool AppBannerSettingsHelper::ShouldUseSiteEngagementScore() {
+  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kEnableSiteEngagementAppBanner)) {
+    return true;
+  }
+
+  // This experiment is controlled under the same key as the broader site
+  // engagement experiment rather than the banner experiment. This avoids cross
+  // pollution with other site engagement experiments. However, this experiment
+  // must only be active when there is one singular group under the banner
+  // experiment, otherwise the banner and site engagement banner experiments
+  // will conflict.
+  //
+  // Making the experiment active when a variations key is present allows us
+  // to have experiments which enable multiple features under site engagement.
+  std::string param = variations::GetVariationParamValue(
+      SiteEngagementService::kEngagementParams, kBannerSiteEngagementParamsKey);
+  return !param.empty();
 }
diff --git a/chrome/browser/banners/app_banner_settings_helper.h b/chrome/browser/banners/app_banner_settings_helper.h
index 3ff877c0..b46bc168 100644
--- a/chrome/browser/banners/app_banner_settings_helper.h
+++ b/chrome/browser/banners/app_banner_settings_helper.h
@@ -117,6 +117,14 @@
       const std::string& package_name_or_start_url,
       AppBannerEvent event);
 
+  // Record a UMA statistic measuring the minutes between the first visit to the
+  // site and the first showing of the banner.
+  static void RecordMinutesFromFirstVisitToShow(
+      content::WebContents* web_contents,
+      const GURL& origin_url,
+      const std::string& package_name_or_start_url,
+      base::Time time);
+
   // Set the engagement weights assigned to direct and indirect navigations.
   static void SetEngagementWeights(double direct_engagement,
                                    double indirect_engagement);
@@ -137,6 +145,10 @@
   // Updates all values from field trial.
   static void UpdateFromFieldTrial();
 
+  // Returns true if the app banner trigger condition should use the site
+  // engagement score instead of the navigation-based heuristic.
+  static bool ShouldUseSiteEngagementScore();
+
  private:
   DISALLOW_IMPLICIT_CONSTRUCTORS(AppBannerSettingsHelper);
 };
diff --git a/chrome/browser/banners/app_banner_settings_helper_unittest.cc b/chrome/browser/banners/app_banner_settings_helper_unittest.cc
index 82550f1..254758a 100644
--- a/chrome/browser/banners/app_banner_settings_helper_unittest.cc
+++ b/chrome/browser/banners/app_banner_settings_helper_unittest.cc
@@ -4,8 +4,14 @@
 
 #include <vector>
 
+#include "base/command_line.h"
+#include "chrome/browser/banners/app_banner_metrics.h"
 #include "chrome/browser/banners/app_banner_settings_helper.h"
+#include "chrome/browser/engagement/site_engagement_service.h"
+#include "chrome/browser/engagement/site_engagement_service_factory.h"
+#include "chrome/common/chrome_switches.h"
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
+#include "chrome/test/base/testing_profile.h"
 #include "ui/base/page_transition_types.h"
 
 namespace {
@@ -731,3 +737,93 @@
   EXPECT_TRUE(AppBannerSettingsHelper::ShouldShowBanner(
       web_contents(), url, kTestPackageName, reference_time));
 }
+
+TEST_F(AppBannerSettingsHelperTest, ShouldShowWithHigherTotal) {
+  AppBannerSettingsHelper::SetEngagementWeights(1, 1);
+  AppBannerSettingsHelper::SetTotalEngagementToTrigger(5);
+  GURL url(kTestURL);
+  NavigateAndCommit(url);
+
+  base::Time reference_time = GetReferenceTime();
+  base::Time second_day = reference_time + base::TimeDelta::FromDays(1);
+  base::Time third_day = reference_time + base::TimeDelta::FromDays(2);
+  base::Time fourth_day = reference_time + base::TimeDelta::FromDays(3);
+  base::Time fifth_day = reference_time + base::TimeDelta::FromDays(4);
+
+  EXPECT_FALSE(AppBannerSettingsHelper::ShouldShowBanner(
+      web_contents(), url, kTestPackageName, reference_time));
+
+  // It should take five visits to trigger the banner.
+  AppBannerSettingsHelper::RecordBannerCouldShowEvent(
+      web_contents(), url, kTestPackageName, reference_time,
+      ui::PAGE_TRANSITION_LINK);
+  EXPECT_FALSE(AppBannerSettingsHelper::ShouldShowBanner(
+      web_contents(), url, kTestPackageName, reference_time));
+
+  AppBannerSettingsHelper::RecordBannerCouldShowEvent(
+      web_contents(), url, kTestPackageName, second_day,
+      ui::PAGE_TRANSITION_TYPED);
+  EXPECT_FALSE(AppBannerSettingsHelper::ShouldShowBanner(
+      web_contents(), url, kTestPackageName, second_day));
+
+  AppBannerSettingsHelper::RecordBannerCouldShowEvent(
+      web_contents(), url, kTestPackageName, third_day,
+      ui::PAGE_TRANSITION_GENERATED);
+  EXPECT_FALSE(AppBannerSettingsHelper::ShouldShowBanner(
+      web_contents(), url, kTestPackageName, third_day));
+
+  AppBannerSettingsHelper::RecordBannerCouldShowEvent(
+      web_contents(), url, kTestPackageName, fourth_day,
+      ui::PAGE_TRANSITION_LINK);
+  EXPECT_FALSE(AppBannerSettingsHelper::ShouldShowBanner(
+      web_contents(), url, kTestPackageName, fourth_day));
+
+  // Visit the site again; now it should be shown.
+  AppBannerSettingsHelper::RecordBannerCouldShowEvent(
+      web_contents(), url, kTestPackageName, fifth_day,
+      ui::PAGE_TRANSITION_TYPED);
+  EXPECT_TRUE(AppBannerSettingsHelper::ShouldShowBanner(
+      web_contents(), url, kTestPackageName, fifth_day));
+}
+
+// Test that the banner triggers correctly using site engagement.
+TEST_F(AppBannerSettingsHelperTest, SiteEngagementTrigger) {
+  AppBannerSettingsHelper::SetTotalEngagementToTrigger(2);
+  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+  command_line->AppendSwitch(switches::kEnableSiteEngagementAppBanner);
+
+  SiteEngagementService* service =
+      SiteEngagementServiceFactory::GetForProfile(profile());
+  DCHECK(service);
+
+  // Not used, but needed for method call.
+  base::Time reference_time = GetReferenceTime();
+  GURL url(kTestURL);
+
+  EXPECT_FALSE(AppBannerSettingsHelper::ShouldShowBanner(
+      web_contents(), url, kTestPackageName, reference_time));
+
+  service->AddPoints(url, 1);
+  EXPECT_FALSE(AppBannerSettingsHelper::ShouldShowBanner(
+      web_contents(), url, kTestPackageName, reference_time));
+
+  service->AddPoints(url, 1);
+  EXPECT_TRUE(AppBannerSettingsHelper::ShouldShowBanner(
+      web_contents(), url, kTestPackageName, reference_time));
+
+  AppBannerSettingsHelper::SetTotalEngagementToTrigger(5);
+  EXPECT_FALSE(AppBannerSettingsHelper::ShouldShowBanner(
+      web_contents(), url, kTestPackageName, reference_time));
+
+  service->AddPoints(url, 1.5);
+  EXPECT_FALSE(AppBannerSettingsHelper::ShouldShowBanner(
+      web_contents(), url, kTestPackageName, reference_time));
+
+  service->AddPoints(url, 0.5);
+  EXPECT_FALSE(AppBannerSettingsHelper::ShouldShowBanner(
+      web_contents(), url, kTestPackageName, reference_time));
+
+  service->AddPoints(url, 1.5);
+  EXPECT_TRUE(AppBannerSettingsHelper::ShouldShowBanner(
+      web_contents(), url, kTestPackageName, reference_time));
+}
diff --git a/chrome/browser/bookmarks/bookmark_model_factory.cc b/chrome/browser/bookmarks/bookmark_model_factory.cc
index b4be798b5..faef18ce 100644
--- a/chrome/browser/bookmarks/bookmark_model_factory.cc
+++ b/chrome/browser/bookmarks/bookmark_model_factory.cc
@@ -16,6 +16,7 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/undo/bookmark_undo_service_factory.h"
 #include "chrome/common/chrome_switches.h"
+#include "chrome/common/features.h"
 #include "chrome/common/pref_names.h"
 #include "components/bookmarks/browser/bookmark_model.h"
 #include "components/bookmarks/browser/bookmark_utils.h"
@@ -24,11 +25,11 @@
 #include "components/undo/bookmark_undo_service.h"
 #include "content/public/browser/browser_thread.h"
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
 #include "chrome/browser/android/offline_pages/offline_page_model_factory.h"
 #include "components/offline_pages/offline_page_feature.h"
 #include "components/offline_pages/offline_page_model.h"
-#endif  // defined(OS_ANDROID)
+#endif  // BUILDFLAG(ANDROID_JAVA_UI)
 
 using bookmarks::BookmarkModel;
 
@@ -56,7 +57,7 @@
   DependsOn(BookmarkUndoServiceFactory::GetInstance());
   DependsOn(ChromeBookmarkClientFactory::GetInstance());
   DependsOn(StartupTaskRunnerServiceFactory::GetInstance());
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
   if (offline_pages::IsOfflinePagesEnabled())
     DependsOn(offline_pages::OfflinePageModelFactory::GetInstance());
 #endif
@@ -80,20 +81,20 @@
                        content::BrowserThread::GetMessageLoopProxyForThread(
                            content::BrowserThread::UI));
   bool register_bookmark_undo_service_as_observer = true;
-#if !defined(OS_IOS) && !defined(OS_ANDROID)
+#if !defined(OS_IOS) && !BUILDFLAG(ANDROID_JAVA_UI)
   register_bookmark_undo_service_as_observer =
       base::CommandLine::ForCurrentProcess()->HasSwitch(
           switches::kEnableBookmarkUndo);
-#endif  // !defined(OS_IOS) && !defined(OS_ANDROID)
+#endif  // !defined(OS_IOS) && !BUILDFLAG(ANDROID_JAVA_UI)
   if (register_bookmark_undo_service_as_observer)
     BookmarkUndoServiceFactory::GetForProfile(profile)->Start(bookmark_model);
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
   if (offline_pages::IsOfflinePagesEnabled()) {
     offline_pages::OfflinePageModelFactory::GetForBrowserContext(profile)->
         Start(bookmark_model);
   }
-#endif  // defined(OS_ANDROID)
+#endif  // BUILDFLAG(ANDROID_JAVA_UI)
 
   return bookmark_model;
 }
diff --git a/chrome/browser/browser_process_impl.cc b/chrome/browser/browser_process_impl.cc
index 603dff56..467f552 100644
--- a/chrome/browser/browser_process_impl.cc
+++ b/chrome/browser/browser_process_impl.cc
@@ -69,6 +69,7 @@
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/extensions/chrome_extensions_client.h"
+#include "chrome/common/features.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/switch_utils.h"
 #include "chrome/common/url_constants.h"
@@ -837,10 +838,10 @@
 #endif  // defined(OS_CHROMEOS)
   registry->RegisterBooleanPref(metrics::prefs::kMetricsReportingEnabled,
                                 GoogleUpdateSettings::GetCollectStatsConsent());
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
   registry->RegisterBooleanPref(
       prefs::kCrashReportingEnabled, false);
-#endif  // defined(OS_ANDROID)
+#endif  // BUILDFLAG(ANDROID_JAVA_UI)
 }
 
 DownloadRequestLimiter* BrowserProcessImpl::download_request_limiter() {
diff --git a/chrome/browser/browser_resources.grd b/chrome/browser/browser_resources.grd
index e41e967..f8e2f4d 100644
--- a/chrome/browser/browser_resources.grd
+++ b/chrome/browser/browser_resources.grd
@@ -153,6 +153,9 @@
         <include name="IDR_MD_EXTENSIONS_ITEM_CSS" file="resources\md_extensions\item.css" type="BINDATA" />
         <include name="IDR_MD_EXTENSIONS_ITEM_HTML" file="resources\md_extensions\item.html" type="BINDATA" />
         <include name="IDR_MD_EXTENSIONS_ITEM_JS" file="resources\md_extensions\item.js" type="BINDATA" />
+        <include name="IDR_MD_EXTENSIONS_ITEM_LIST_CSS" file="resources\md_extensions\item_list.css" type="BINDATA" />
+        <include name="IDR_MD_EXTENSIONS_ITEM_LIST_HTML" file="resources\md_extensions\item_list.html" type="BINDATA" />
+        <include name="IDR_MD_EXTENSIONS_ITEM_LIST_JS" file="resources\md_extensions\item_list.js" type="BINDATA" />
         <include name="IDR_MD_EXTENSIONS_SERVICE_HTML" file="resources\md_extensions\service.html" type="BINDATA" />
         <include name="IDR_MD_EXTENSIONS_SERVICE_JS" file="resources\md_extensions\service.js" type="BINDATA" />
         <include name="IDR_MD_EXTENSIONS_SIDEBAR_CSS" file="resources\md_extensions\sidebar.css" type="BINDATA" />
diff --git a/chrome/browser/browsing_data/browsing_data_remover.cc b/chrome/browser/browsing_data/browsing_data_remover.cc
index f8865d3..7779d42 100644
--- a/chrome/browser/browsing_data/browsing_data_remover.cc
+++ b/chrome/browser/browsing_data/browsing_data_remover.cc
@@ -39,6 +39,7 @@
 #include "chrome/browser/sessions/session_service_factory.h"
 #include "chrome/browser/sessions/tab_restore_service_factory.h"
 #include "chrome/browser/web_data_service_factory.h"
+#include "chrome/common/features.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/url_constants.h"
 #include "components/autofill/core/browser/personal_data_manager.h"
@@ -76,7 +77,7 @@
 #include "storage/browser/quota/special_storage_policy.h"
 #include "url/origin.h"
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
 #include "chrome/browser/android/offline_pages/offline_page_model_factory.h"
 #include "chrome/browser/android/webapps/webapp_registry.h"
 #include "chrome/browser/precache/precache_manager_factory.h"
@@ -429,7 +430,7 @@
     if (profile_->GetSSLHostStateDelegate())
       profile_->GetSSLHostStateDelegate()->Clear();
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
     precache::PrecacheManager* precache_manager =
         precache::PrecacheManagerFactory::GetForBrowserContext(profile_);
     // |precache_manager| could be nullptr if the profile is off the record.
@@ -801,7 +802,7 @@
     }
   }
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
   if (remove_mask & REMOVE_WEBAPP_DATA) {
     waiting_for_clear_webapp_data_ = true;
     WebappRegistry::UnregisterWebapps(
@@ -897,7 +898,7 @@
          !waiting_for_clear_platform_keys_ &&
          !waiting_for_clear_plugin_data_ &&
          !waiting_for_clear_pnacl_cache_ &&
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
          !waiting_for_clear_precache_history_ &&
          !waiting_for_clear_webapp_data_ &&
          !waiting_for_clear_offline_page_data_ &&
@@ -1193,7 +1194,7 @@
 }
 #endif
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
 void BrowsingDataRemover::OnClearedPrecacheHistory() {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   waiting_for_clear_precache_history_ = false;
diff --git a/chrome/browser/browsing_data/browsing_data_remover.h b/chrome/browser/browsing_data/browsing_data_remover.h
index 62cd36ea..fd04850 100644
--- a/chrome/browser/browsing_data/browsing_data_remover.h
+++ b/chrome/browser/browsing_data/browsing_data_remover.h
@@ -16,6 +16,7 @@
 #include "base/task/cancelable_task_tracker.h"
 #include "base/time/time.h"
 #include "chrome/browser/pepper_flash_settings_manager.h"
+#include "chrome/common/features.h"
 #include "components/search_engines/template_url_service.h"
 #if defined(OS_CHROMEOS)
 #include "chromeos/dbus/dbus_method_call_status.h"
@@ -83,7 +84,7 @@
     REMOVE_NOCHECKS = 1 << 16,
     REMOVE_WEBRTC_IDENTITY = 1 << 17,
     REMOVE_CACHE_STORAGE = 1 << 18,
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
     REMOVE_WEBAPP_DATA = 1 << 19,
     REMOVE_OFFLINE_PAGE_DATA = 1 << 20,
 #endif
@@ -104,7 +105,7 @@
                        REMOVE_WEBSQL |
                        REMOVE_CHANNEL_IDS |
                        REMOVE_SITE_USAGE_DATA |
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
                        REMOVE_WEBAPP_DATA |
                        REMOVE_OFFLINE_PAGE_DATA |
 #endif
@@ -397,7 +398,7 @@
   void OnClearedWebRtcLogs();
 #endif
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
   // Callback on UI thread when the precache history has been cleared.
   void OnClearedPrecacheHistory();
 
@@ -465,7 +466,7 @@
   bool waiting_for_clear_platform_keys_ = false;
   bool waiting_for_clear_plugin_data_ = false;
   bool waiting_for_clear_pnacl_cache_ = false;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
   bool waiting_for_clear_precache_history_ = false;
   bool waiting_for_clear_webapp_data_ = false;
   bool waiting_for_clear_offline_page_data_ = false;
diff --git a/chrome/browser/chrome_browser_main.cc b/chrome/browser/chrome_browser_main.cc
index 3a41ca91b..6f18aad0 100644
--- a/chrome/browser/chrome_browser_main.cc
+++ b/chrome/browser/chrome_browser_main.cc
@@ -97,6 +97,7 @@
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/crash_keys.h"
 #include "chrome/common/env_vars.h"
+#include "chrome/common/features.h"
 #include "chrome/common/logging_chrome.h"
 #include "chrome/common/net/net_resource_provider.h"
 #include "chrome/common/pref_names.h"
@@ -150,12 +151,16 @@
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/strings/grit/app_locale_settings.h"
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
 #include "chrome/browser/android/dev_tools_discovery_provider_android.h"
+#else
+#include "chrome/browser/devtools/chrome_devtools_discovery_provider.h"
+#endif
+
+#if defined(OS_ANDROID)
 #include "chrome/browser/metrics/thread_watcher_android.h"
 #include "ui/base/resource/resource_bundle_android.h"
 #else
-#include "chrome/browser/devtools/chrome_devtools_discovery_provider.h"
 #include "chrome/browser/feedback/feedback_profile_observer.h"
 #endif  // defined(OS_ANDROID)
 
@@ -789,6 +794,8 @@
   // On Android, first run is handled in Java code, and the C++ side of Chrome
   // doesn't know if this is the first run. This will cause some inaccuracy in
   // the UMA statistics, but this should be minor (first runs are rare).
+  // TODO(bshe): Figure out which first run code to use for Aura Android. See
+  // crbug.com/560498
   is_first_run = first_run::IsChromeFirstRun();
 #endif  // defined(OS_ANDROID)
 
@@ -862,11 +869,13 @@
   result_code_ = PreCreateThreadsImpl();
 
   if (result_code_ == content::RESULT_CODE_NORMAL_EXIT) {
-#if !defined(OS_ANDROID)
+  // TODO(bshe): Use !defined(ANDROID_JAVA_UI) once
+  // codereview.chromium.org/1459793002 landed.
+#if !defined(OS_ANDROID) || defined(USE_AURA)
     // These members must be initialized before exiting this function normally.
     DCHECK(master_prefs_.get());
     DCHECK(browser_creator_.get());
-#endif  // !defined(OS_ANDROID)
+#endif  // !defined(OS_ANDROID) || defined(USE_AURA)
     for (size_t i = 0; i < chrome_extra_parts_.size(); ++i)
       chrome_extra_parts_[i]->PreCreateThreads();
   }
@@ -887,6 +896,8 @@
   MediaCaptureDevicesDispatcher::GetInstance();
 
   // Android's first run is done in Java instead of native.
+  // TODO(bshe): Figure out which first run code to use for Aura Android. See
+  // crbug.com/560498
 #if !defined(OS_ANDROID)
   process_singleton_.reset(new ChromeProcessSingleton(
       user_data_dir_, base::Bind(&ProcessSingletonNotificationCallback)));
@@ -924,14 +935,16 @@
   local_state_ = InitializeLocalState(
       local_state_task_runner.get(), parsed_command_line());
 
-#if !defined(OS_ANDROID)
+  // TODO(bshe): Use !defined(ANDROID_JAVA_UI) once
+  // codereview.chromium.org/1459793002 landed.
+#if !defined(OS_ANDROID) || defined(USE_AURA)
   // These members must be initialized before returning from this function.
   master_prefs_.reset(new first_run::MasterPrefs);
   // Android doesn't use StartupBrowserCreator.
   browser_creator_.reset(new StartupBrowserCreator);
   // TODO(yfriedman): Refactor Android to re-use UMABrowsingActivityObserver
   chrome::UMABrowsingActivityObserver::Init();
-#endif  // !defined(OS_ANDROID)
+#endif  // !defined(OS_ANDROID) || defined(USE_AURA)
 
 #if !defined(OS_CHROMEOS)
   // Convert active labs into switches. This needs to be done before
@@ -1006,6 +1019,7 @@
     base::FilePath resources_pack_path;
     PathService::Get(chrome::FILE_RESOURCES_PACK, &resources_pack_path);
 #if defined(OS_ANDROID)
+    // Uses Android resources even without ANDROID_JAVA_UI.
     ui::LoadMainAndroidPackFile("assets/resources.pak", resources_pack_path);
 #else
     ResourceBundle::GetSharedInstance().AddDataPackFromPath(
@@ -1016,6 +1030,8 @@
 
   // Android does first run in Java instead of native.
   // Chrome OS has its own out-of-box-experience code.
+  // TODO(bshe): Figure out which first run code to use for Aura Android. See
+  // crbug.com/560498
 #if !defined(OS_ANDROID) && !defined(OS_CHROMEOS)
   // On first run, we need to process the predictor preferences before the
   // browser's profile_manager object is created, but after ResourceBundle
@@ -1163,11 +1179,11 @@
 void ChromeBrowserMainParts::PostProfileInit() {
   TRACE_EVENT0("startup", "ChromeBrowserMainParts::PostProfileInit");
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
   DevToolsDiscoveryProviderAndroid::Install();
 #else
   ChromeDevToolsDiscoveryProvider::Install();
-#endif  // defined(OS_ANDROID)
+#endif  // BUILDFLAG(ANDROID_JAVA_UI)
 
   LaunchDevToolsHandlerIfNeeded(parsed_command_line());
   for (size_t i = 0; i < chrome_extra_parts_.size(); ++i)
@@ -1449,12 +1465,14 @@
   if (!profile_)
     return content::RESULT_CODE_NORMAL_EXIT;
 
-#if !defined(OS_ANDROID)
+  // TODO(bshe): Use !defined(ANDROID_JAVA_UI) once
+  // codereview.chromium.org/1459793002 landed.
+#if !defined(OS_ANDROID) || defined(USE_AURA)
   const base::TimeTicks start_time_step2 = base::TimeTicks::Now();
   // The first run sentinel must be created after the process singleton was
   // grabbed and no early return paths were otherwise hit above.
   first_run::CreateSentinelIfNeeded();
-#endif  // !defined(OS_ANDROID)
+#endif  // !defined(OS_ANDROID) || defined(USE_AURA)
 
 #if defined(ENABLE_BACKGROUND)
   // Autoload any profiles which are running background apps.
@@ -1496,6 +1514,8 @@
   // Note that this be done _after_ the PrefService is initialized and all
   // preferences are registered, since some of the code that the importer
   // touches reads preferences.
+  // TODO(bshe): Figure out which first run code to use for Aura Android. See
+  // crbug.com/560498
   if (first_run::IsChromeFirstRun()) {
     first_run::AutoImport(profile_,
                           master_prefs_->homepage_defined,
@@ -1630,9 +1650,10 @@
       g_browser_process->local_state());
   ThreadWatcherList::StartWatchingAll(parsed_command_line());
 
-#if defined(OS_ANDROID)
+  // TODO(bshe): Aura Android may need this call. See crbug.com/565317.
+#if defined(OS_ANDROID) && !defined(USE_AURA)
   ThreadWatcherAndroid::RegisterApplicationStatusListener();
-#endif  // defined(OS_ANDROID)
+#endif  // defined(OS_ANDROID) && !defined(USE_AURA)
 
 #if !defined(DISABLE_NACL)
   BrowserThread::PostTask(
@@ -1659,7 +1680,9 @@
   if (!parsed_command_line().HasSwitch(switches::kDisableComponentUpdate))
     RegisterComponentsForUpdate();
 
-#if defined(OS_ANDROID)
+  // TODO(bshe): Use defined(ANDROID_JAVA_UI) once
+  // codereview.chromium.org/1459793002 landed.
+#if defined(OS_ANDROID) && !defined(USE_AURA)
   variations::VariationsService* variations_service =
       browser_process_->variations_service();
   if (variations_service) {
@@ -1669,7 +1692,6 @@
   }
   translate::TranslateDownloadManager::RequestLanguageList(
       profile_->GetPrefs());
-
 #else
   // Most general initialization is behind us, but opening a
   // tab and/or session restore and such is still to be done.
@@ -1746,9 +1768,11 @@
     content::StartPowerUsageMonitor();
 #endif  // !defined(OS_LINUX) || defined(OS_CHROMEOS)
 
+#if !defined(OS_ANDROID)
   process_power_collector_.reset(new ProcessPowerCollector);
   process_power_collector_->Initialize();
 #endif  // !defined(OS_ANDROID)
+#endif  // defined(OS_ANDROID) && !defined(USE_AURA)
 
   PostBrowserStart();
 
@@ -1766,10 +1790,12 @@
   }
 #endif  // defined(OS_ANDROID)
 
-#if !defined(OS_ANDROID)
+  // TODO(bshe): Use !defined(ANDROID_JAVA_UI) once
+  // codereview.chromium.org/1459793002 landed.
+#if !defined(OS_ANDROID) || defined(USE_AURA)
   UMA_HISTOGRAM_TIMES("Startup.PreMainMessageLoopRunImplStep3Time",
                       base::TimeTicks::Now() - start_time_step3);
-#endif  // !defined(OS_ANDROID)
+#endif  // !defined(OS_ANDROID) || defined(USE_AURA)
 
   return result_code_;
 }
diff --git a/chrome/browser/chrome_browser_main.h b/chrome/browser/chrome_browser_main.h
index 140a960..e142ad2 100644
--- a/chrome/browser/chrome_browser_main.h
+++ b/chrome/browser/chrome_browser_main.h
@@ -164,7 +164,10 @@
 
   scoped_ptr<BrowserProcessImpl> browser_process_;
   scoped_refptr<metrics::TrackingSynchronizer> tracking_synchronizer_;
-#if !defined(OS_ANDROID)
+
+  // TODO(bshe): Use !defined(ANDROID_JAVA_UI) once
+  // codereview.chromium.org/1459793002 landed.
+#if !defined(OS_ANDROID) || defined(USE_AURA)
   // Browser creation happens on the Java side in Android.
   scoped_ptr<StartupBrowserCreator> browser_creator_;
 
@@ -174,7 +177,7 @@
 
   // Android's first run is done in Java instead of native.
   scoped_ptr<first_run::MasterPrefs> master_prefs_;
-#endif
+#endif  // !defined(OS_ANDROID) || defined(USE_AURA)
   Profile* profile_;
   bool run_message_loop_;
   ProcessSingleton::NotifyResult notify_result_;
diff --git a/chrome/browser/chrome_browser_main_extra_parts_exo.cc b/chrome/browser/chrome_browser_main_extra_parts_exo.cc
index d13c14d9..9cecfbd3 100644
--- a/chrome/browser/chrome_browser_main_extra_parts_exo.cc
+++ b/chrome/browser/chrome_browser_main_extra_parts_exo.cc
@@ -4,10 +4,6 @@
 
 #include "chrome/browser/chrome_browser_main_extra_parts_exo.h"
 
-#if defined(USE_GLIB)
-#include <glib.h>
-#endif
-
 #include "base/command_line.h"
 #include "base/message_loop/message_loop.h"
 #include "chrome/browser/ui/ash/ash_util.h"
@@ -16,61 +12,6 @@
 #include "components/exo/wayland/server.h"
 #include "content/public/browser/browser_thread.h"
 
-#if defined(USE_GLIB)
-namespace {
-
-gboolean WaylandSourcePrepare(GSource* source, gint* timeout_ms) {
-  *timeout_ms = -1;
-  return FALSE;
-}
-
-gboolean WaylandSourceCheck(GSource* source) {
-  return TRUE;
-}
-
-gboolean WaylandSourceDispatch(GSource* source,
-                               GSourceFunc unused_func,
-                               gpointer data) {
-  exo::wayland::Server* server = static_cast<exo::wayland::Server*>(data);
-  server->Dispatch(base::TimeDelta());
-  server->Flush();
-  return TRUE;
-}
-
-GSourceFuncs g_wayland_source_funcs = {WaylandSourcePrepare, WaylandSourceCheck,
-                                       WaylandSourceDispatch, nullptr};
-
-}  // namespace
-
-class ChromeBrowserMainExtraPartsExo::WaylandWatcher {
- public:
-  explicit WaylandWatcher(exo::wayland::Server* server)
-      : wayland_poll_(new GPollFD),
-        wayland_source_(
-            g_source_new(&g_wayland_source_funcs, sizeof(GSource))) {
-    wayland_poll_->fd = server->GetFileDescriptor();
-    wayland_poll_->events = G_IO_IN;
-    wayland_poll_->revents = 0;
-    g_source_add_poll(wayland_source_, wayland_poll_.get());
-    g_source_set_can_recurse(wayland_source_, TRUE);
-    g_source_set_callback(wayland_source_, nullptr, server, nullptr);
-    g_source_attach(wayland_source_, g_main_context_default());
-  }
-  ~WaylandWatcher() {
-    g_source_destroy(wayland_source_);
-    g_source_unref(wayland_source_);
-  }
-
- private:
-  // The poll attached to |wayland_source_|.
-  scoped_ptr<GPollFD> wayland_poll_;
-
-  // The GLib event source for wayland events.
-  GSource* wayland_source_;
-
-  DISALLOW_COPY_AND_ASSIGN(WaylandWatcher);
-};
-#else
 class ChromeBrowserMainExtraPartsExo::WaylandWatcher
     : public base::MessagePumpLibevent::Watcher {
  public:
@@ -94,7 +35,6 @@
 
   DISALLOW_COPY_AND_ASSIGN(WaylandWatcher);
 };
-#endif
 
 ChromeBrowserMainExtraPartsExo::ChromeBrowserMainExtraPartsExo()
     : display_(new exo::Display) {}
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index e0707b57..14ee957 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -93,6 +93,7 @@
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/env_vars.h"
+#include "chrome/common/features.h"
 #include "chrome/common/logging_chrome.h"
 #include "chrome/common/pepper_permission_util.h"
 #include "chrome/common/pref_names.h"
@@ -197,6 +198,12 @@
 #include "components/crash/content/browser/crash_handler_host_linux.h"
 #endif
 
+#if BUILDFLAG(ANDROID_JAVA_UI)
+#include "chrome/browser/android/new_tab_page_url_handler.h"
+#include "chrome/browser/android/webapps/single_tab_mode_tab_helper.h"
+#include "components/service_tab_launcher/browser/android/service_tab_launcher.h"
+#endif
+
 #if defined(OS_ANDROID)
 #include "ui/base/ui_base_paths.h"
 #include "ui/gfx/android/device_display_info.h"
@@ -277,12 +284,6 @@
 #include "chrome/browser/chrome_browser_main_extra_parts_exo.h"
 #endif
 
-#if defined(OS_ANDROID) && !defined(USE_AURA)
-#include "chrome/browser/android/new_tab_page_url_handler.h"
-#include "chrome/browser/android/webapps/single_tab_mode_tab_helper.h"
-#include "components/service_tab_launcher/browser/android/service_tab_launcher.h"
-#endif
-
 using base::FileDescriptor;
 using blink::WebWindowFeatures;
 using content::AccessTokenStore;
@@ -589,10 +590,7 @@
       safe_browsing_ui_manager_;
 };
 
-
-  // TODO(bshe): Use defined(ANDROID_JAVA_UI) once
-  // codereview.chromium.org/1459793002 landed.
-#if defined(OS_ANDROID) && !defined(USE_AURA)
+#if BUILDFLAG(ANDROID_JAVA_UI)
 void HandleSingleTabModeBlockOnUIThread(const BlockedWindowParams& params) {
   WebContents* web_contents = tab_util::GetWebContentsByFrameID(
       params.render_process_id(), params.opener_render_frame_id());
@@ -601,7 +599,7 @@
 
   SingleTabModeTabHelper::FromWebContents(web_contents)->HandleOpenUrl(params);
 }
-#endif
+#endif  // BUILDFLAG(ANDROID_JAVA_UI)
 
 #if defined(OS_ANDROID)
 float GetDeviceScaleAdjustment() {
@@ -2176,9 +2174,7 @@
     }
   }
 
-  // TODO(bshe): Use defined(ANDROID_JAVA_UI) once
-  // codereview.chromium.org/1459793002 landed.
-#if defined(OS_ANDROID) && !defined(USE_AURA)
+#if BUILDFLAG(ANDROID_JAVA_UI)
   if (SingleTabModeTabHelper::IsRegistered(render_process_id,
                                            opener_render_view_id)) {
     BrowserThread::PostTask(BrowserThread::UI,
@@ -2294,7 +2290,6 @@
   web_prefs->password_echo_enabled = browser_defaults::kPasswordEchoEnabled;
 #endif
 
-  web_prefs->asynchronous_spell_checking_enabled = true;
   web_prefs->unified_textchecker_enabled = true;
 
   web_prefs->uses_universal_detector =
@@ -2349,9 +2344,7 @@
   handler->AddHandlerPair(&WillHandleBrowserAboutURL,
                           BrowserURLHandler::null_handler());
 
-  // TODO(bshe): Use defined(ANDROID_JAVA_UI) once
-  // codereview.chromium.org/1459793002 landed.
-#if defined(OS_ANDROID) && !defined(USE_AURA)
+#if BUILDFLAG(ANDROID_JAVA_UI)
   // Handler to rewrite chrome://newtab on Android.
   handler->AddHandlerPair(&chrome::android::HandleAndroidNativePageURL,
                           BrowserURLHandler::null_handler());
@@ -2637,9 +2630,10 @@
     const base::Callback<void(content::WebContents*)>& callback) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
-  // TODO(bshe): Use !defined(ANDROID_JAVA_UI) once
-  // codereview.chromium.org/1459793002 landed.
-#if (!defined(OS_ANDROID) || defined(USE_AURA)) && !defined(OS_IOS)
+#if BUILDFLAG(ANDROID_JAVA_UI)
+  service_tab_launcher::ServiceTabLauncher::GetInstance()->LaunchTab(
+      browser_context, params, callback);
+#elif !defined(OS_IOS)
   chrome::NavigateParams nav_params(
       Profile::FromBrowserContext(browser_context),
       params.url,
@@ -2649,9 +2643,6 @@
 
   Navigate(&nav_params);
   callback.Run(nav_params.target_contents);
-#elif defined(OS_ANDROID)
-  service_tab_launcher::ServiceTabLauncher::GetInstance()->LaunchTab(
-      browser_context, params, callback);
 #else
   NOTIMPLEMENTED();
 #endif
diff --git a/chrome/browser/chromeos/app_mode/fake_cws.cc b/chrome/browser/chromeos/app_mode/fake_cws.cc
index a1f25c4..43474b5 100644
--- a/chrome/browser/chromeos/app_mode/fake_cws.cc
+++ b/chrome/browser/chromeos/app_mode/fake_cws.cc
@@ -93,6 +93,8 @@
   update_check_end_point_ = update_check_end_point;
 
   SetupWebStoreURL(embedded_test_server->base_url());
+  OverrideGalleryCommandlineSwitches();
+
   embedded_test_server->RegisterRequestHandler(
       base::Bind(&FakeCWS::HandleRequest, base::Unretained(this)));
 }
diff --git a/chrome/browser/chromeos/app_mode/startup_app_launcher.cc b/chrome/browser/chromeos/app_mode/startup_app_launcher.cc
index 15156245..fed5be6a 100644
--- a/chrome/browser/chromeos/app_mode/startup_app_launcher.cc
+++ b/chrome/browser/chromeos/app_mode/startup_app_launcher.cc
@@ -72,12 +72,7 @@
     : profile_(profile),
       app_id_(app_id),
       diagnostic_mode_(diagnostic_mode),
-      delegate_(delegate),
-      network_ready_handled_(false),
-      launch_attempt_(0),
-      ready_to_launch_(false),
-      wait_for_crx_update_(false),
-      secondary_apps_updated_(false) {
+      delegate_(delegate) {
   DCHECK(profile_);
   DCHECK(crx_file::id_util::IdIsValid(app_id_));
   KioskAppManager::Get()->AddObserver(this);
@@ -269,6 +264,59 @@
   }
 }
 
+void StartupAppLauncher::MaybeCheckExtensionUpdate() {
+  extensions::ExtensionUpdater* updater =
+      extensions::ExtensionSystem::Get(profile_)
+          ->extension_service()
+          ->updater();
+  if (!delegate_->IsNetworkReady() || !updater) {
+    MaybeLaunchApp();
+    return;
+  }
+
+  extension_update_found_ = false;
+  registrar_.Add(this, extensions::NOTIFICATION_EXTENSION_UPDATE_FOUND,
+                 content::NotificationService::AllSources());
+
+  // Enforce an immediate version update check for all extensions before
+  // launching the primary app. After the chromeos is updated, the shared
+  // module(e.g. ARC runtime) may need to be updated to a newer version
+  // compatible with the new chromeos. See crbug.com/555083.
+  extensions::ExtensionUpdater::CheckParams params;
+  params.install_immediately = true;
+  params.callback = base::Bind(
+      &StartupAppLauncher::OnExtensionUpdateCheckFinished, AsWeakPtr());
+  updater->CheckNow(params);
+}
+
+void StartupAppLauncher::OnExtensionUpdateCheckFinished() {
+  if (extension_update_found_) {
+    // Reload the primary app to make sure any reference to the previous version
+    // of the shared module, extension, etc will be cleaned up andthe new
+    // version will be loaded.
+    extensions::ExtensionSystem::Get(profile_)
+            ->extension_service()
+            ->ReloadExtension(app_id_);
+    extension_update_found_ = false;
+  }
+  registrar_.Remove(this, extensions::NOTIFICATION_EXTENSION_UPDATE_FOUND,
+                    content::NotificationService::AllSources());
+
+  MaybeLaunchApp();
+}
+
+void StartupAppLauncher::Observe(int type,
+                                 const content::NotificationSource& source,
+                                 const content::NotificationDetails& details) {
+  DCHECK(type == extensions::NOTIFICATION_EXTENSION_UPDATE_FOUND);
+  typedef const std::pair<std::string, Version> UpdateDetails;
+  const std::string& id = content::Details<UpdateDetails>(details)->first;
+  const Version& version = content::Details<UpdateDetails>(details)->second;
+  VLOG(1) << "Found extension update id=" << id
+      << " version=" << version.GetString();
+  extension_update_found_ = true;
+}
+
 void StartupAppLauncher::OnFinishCrxInstall(const std::string& extension_id,
                                             bool success) {
   // Wait for pending updates or dependent extensions to download.
@@ -293,10 +341,10 @@
   }
 
   if (GetPrimaryAppExtension()) {
-    if (!secondary_apps_updated_)
+    if (!secondary_apps_installed_)
       MaybeInstallSecondaryApps();
     else
-      MaybeLaunchApp();
+      MaybeCheckExtensionUpdate();
   }
 }
 
@@ -465,7 +513,7 @@
     return;
   }
 
-  secondary_apps_updated_ = true;
+  secondary_apps_installed_ = true;
   extensions::KioskModeInfo* info =
       extensions::KioskModeInfo::Get(GetPrimaryAppExtension());
   KioskAppManager::Get()->InstallSecondaryApps(info->secondary_app_ids);
@@ -479,8 +527,8 @@
   }
 
   if (AreSecondaryAppsInstalled()) {
-    // Launch the primary app.
-    MaybeLaunchApp();
+    // Check extension update before launching the primary kiosk app.
+    MaybeCheckExtensionUpdate();
   } else {
     OnLaunchFailure(KioskAppLaunchError::UNABLE_TO_INSTALL);
   }
diff --git a/chrome/browser/chromeos/app_mode/startup_app_launcher.h b/chrome/browser/chromeos/app_mode/startup_app_launcher.h
index 3ac3547..d113450 100644
--- a/chrome/browser/chromeos/app_mode/startup_app_launcher.h
+++ b/chrome/browser/chromeos/app_mode/startup_app_launcher.h
@@ -13,6 +13,8 @@
 #include "chrome/browser/chromeos/app_mode/kiosk_app_launch_error.h"
 #include "chrome/browser/chromeos/app_mode/kiosk_app_manager_observer.h"
 #include "chrome/browser/extensions/install_observer.h"
+#include "content/public/browser/notification_observer.h"
+#include "content/public/browser/notification_registrar.h"
 #include "google_apis/gaia/oauth2_token_service.h"
 
 class Profile;
@@ -32,7 +34,8 @@
 class StartupAppLauncher : public base::SupportsWeakPtr<StartupAppLauncher>,
                            public OAuth2TokenService::Observer,
                            public extensions::InstallObserver,
-                           public KioskAppManagerObserver {
+                           public KioskAppManagerObserver,
+                           public content::NotificationObserver {
  public:
   class Delegate {
    public:
@@ -94,6 +97,9 @@
   void MaybeInstallSecondaryApps();
   void MaybeLaunchApp();
 
+  void MaybeCheckExtensionUpdate();
+  void OnExtensionUpdateCheckFinished();
+
   void StartLoadingOAuthFile();
   static void LoadOAuthFileOnBlockingPool(KioskOAuthParams* auth_params);
   void OnOAuthFileLoaded(KioskOAuthParams* auth_params);
@@ -128,17 +134,24 @@
   void OnKioskExtensionLoadedInCache(const std::string& app_id) override;
   void OnKioskExtensionDownloadFailed(const std::string& app_id) override;
 
+  // content::NotificationObserver implementation.
+  void Observe(int type,
+               const content::NotificationSource& source,
+               const content::NotificationDetails& details) override;
+
   Profile* profile_;
   const std::string app_id_;
   const bool diagnostic_mode_;
   Delegate* delegate_;
-  bool network_ready_handled_;
-  int launch_attempt_;
-  bool ready_to_launch_;
-  bool wait_for_crx_update_;
-  bool secondary_apps_updated_;
+  bool network_ready_handled_ = false;
+  int launch_attempt_ = 0;
+  bool ready_to_launch_ = false;
+  bool wait_for_crx_update_ = false;
+  bool secondary_apps_installed_ = false;
+  bool extension_update_found_ = false;
 
   KioskOAuthParams auth_params_;
+  content::NotificationRegistrar registrar_;
 
   DISALLOW_COPY_AND_ASSIGN(StartupAppLauncher);
 };
diff --git a/chrome/browser/chromeos/login/kiosk_browsertest.cc b/chrome/browser/chromeos/login/kiosk_browsertest.cc
index 4322d44..5bc093d5 100644
--- a/chrome/browser/chromeos/login/kiosk_browsertest.cc
+++ b/chrome/browser/chromeos/login/kiosk_browsertest.cc
@@ -117,19 +117,50 @@
 // An app to test local access to file systems via the
 // chrome.fileSystem.requestFileSystem API.
 // Webstore data json is in
-//   chrome/test/data/chromeos/app_mode/webstore/inlineinstall/
-//       detail/aaedpojejpghjkedenggihopfhfijcko
+//     chrome/test/data/chromeos/app_mode/webstore/inlineinstall/
+//         detail/aaedpojejpghjkedenggihopfhfijcko
 const char kTestGetVolumeListKioskApp[] = "aaedpojejpghjkedenggihopfhfijcko";
 
-// Testing apps for testing kiosk multi-app feature.
-const char kTestPrimaryKioskApp[] = "ceobkcclegcliomogfoeoheahogoecgl";
-const char kTestSecondaryApp1[] = "ihplaomghjbeafnpnjkhppmfpnmdihgd";
-const char kTestSecondaryApp2[] = "fiehokkcgaojmbhfhlpiheggjhaedjoc";
-const char kTestSecondaryApp3[] = "aabnpdpieclcikafhdkkpldcaodmfoai";
-const char kTestSecondaryExtension[] = "imlgadjgphbjkaceoiapiephhgeofhic";
+// Testing apps for testing kiosk multi-app feature. All the crx files are in
+//    chrome/test/data/chromeos/app_mode/webstore/downloads.
+
+// Source files are in
+//     chrome/test/data/chromeos/app_mode/multi_app_kiosk/src/primary_app
+const char kTestPrimaryKioskApp[] = "dpejijbnadgcgmabkmcoajkgongfgnii";
+
+// Source files are in
+//     chrome/test/data/chromeos/app_mode/multi_app_kiosk/src/secondary_app_1
+const char kTestSecondaryApp1[] = "emnbflhfbllbehnpjmjddklbkeeoaaeg";
+
+// Source files are in
+//     chrome/test/data/chromeos/app_mode/multi_app_kiosk/src/secondary_app_2
+const char kTestSecondaryApp2[] = "blmjgfbajihimkjmepbhgmjbopjchlda";
+
+// Source files are in
+//     chrome/test/data/chromeos/app_mode/multi_app_kiosk/src/secondary_app_3
+const char kTestSecondaryApp3[] = "jkofhenkpndpdflehcjpcekgecjkpggg";
+
+// Source files are in
+//     chrome/test/data/chromeos/app_mode/multi_app_kiosk/src/
+//         secondary_extensions_1
+const char kTestSecondaryExtension[] = "gdmgkkoghcihimdfoabkefdkccllcfea";
+
+// Source files are in
+//     chrome/test/data/chromeos/app_mode/multi_app_kiosk/src/
+//         shared_module_primary_app
 const char kTestSharedModulePrimaryApp[] = "ofmeihgcmabfalhhgooajcijiaoekhkg";
+
+// Source files are in
+//     chrome/test/data/chromeos/app_mode/multi_app_kiosk/src/secondary_app
 const char kTestSecondaryApp[] = "bbmaiojbgkkmfaglfhaplfomobgojhke";
+
+// Source files are in
+//     chrome/test/data/chromeos/app_mode/multi_app_kiosk/src/shared_module
 const char kTestSharedModuleId[] = "biebhpdepndljbnkadldcbjkiedldnmn";
+
+// Source files are in
+//     chrome/test/data/chromeos/app_mode/multi_app_kiosk/src/
+//         secondary_extension
 const char kTestSecondaryExt[] = "kcoobopfcjmbfeppibolpaolbgbmkcjd";
 
 // Fake usb stick mount path.
@@ -203,14 +234,14 @@
   lock->Release();
 }
 
-bool IsAppInstalled(const std::string& app_id) {
+bool IsAppInstalled(const std::string& app_id, const std::string& version) {
   Profile* app_profile = ProfileManager::GetPrimaryUserProfile();
   DCHECK(app_profile);
   const extensions::Extension* app =
       extensions::ExtensionSystem::Get(app_profile)
           ->extension_service()
           ->GetInstalledExtension(app_id);
-  return app != nullptr;
+  return app != nullptr && version == app->version()->GetString();
 }
 
 extensions::Manifest::Type GetAppType(const std::string& app_id) {
@@ -484,6 +515,9 @@
     settings_helper_.ReplaceProvider(kAccountsPrefDeviceLocalAccounts);
     owner_settings_service_ = settings_helper_.CreateOwnerSettingsService(
         ProfileManager::GetPrimaryUserProfile());
+
+    // Set up local cache for app update check.
+    CreateAndInitializeLocalCache();
   }
 
   void TearDownOnMainThread() override {
@@ -498,6 +532,19 @@
     KioskAppManager::Get()->CleanUp();
   }
 
+  // The local cache is supposed to be initialized on chromeos device, and a
+  // ready flag file will be pre-created to mark the ready state, before chrome
+  // starts. In order for the tests to run without being on real chromeos
+  // device, we need to manually create this file.
+  void CreateAndInitializeLocalCache() {
+    base::FilePath extension_cache_dir;
+    CHECK(PathService::Get(chromeos::DIR_DEVICE_EXTENSION_LOCAL_CACHE,
+                           &extension_cache_dir));
+    base::FilePath cache_init_file = extension_cache_dir.Append(
+        extensions::LocalExtensionCache::kCacheReadyFlagFileName);
+    EXPECT_EQ(base::WriteFile(cache_init_file, "", 0), 0);
+  }
+
   void SetUpCommandLine(base::CommandLine* command_line) override {
     OobeBaseTest::SetUpCommandLine(command_line);
     fake_cws_->Init(embedded_test_server());
@@ -1328,8 +1375,6 @@
     // next startup) and copy the list to our stub settings provider as well.
     settings_helper_.CopyStoredValue(kAccountsPrefDeviceLocalAccounts);
 
-    CreateAndInitializeLocalCache();
-
     KioskTest::SetUpOnMainThread();
   }
 
@@ -1425,9 +1470,9 @@
     WaitForAppLaunchWithOptions(false, true);
 
     // Verify the primary app and the secondary apps are all installed.
-    EXPECT_EQ(primary_app.version, GetInstalledAppVersion().GetString());
+    EXPECT_TRUE(IsAppInstalled(primary_app.id, primary_app.version));
     for (const auto& app : secondary_apps) {
-      EXPECT_TRUE(IsAppInstalled(app.id));
+      EXPECT_TRUE(IsAppInstalled(app.id, app.version));
       EXPECT_EQ(GetAppType(app.id), app.type);
     }
   }
@@ -1484,7 +1529,24 @@
     secondary_apps.push_back(shared_module);
 
     LaunchKioskWithSecondaryApps(primary_app, secondary_apps);
-    EXPECT_TRUE(IsAppInstalled(kTestSharedModuleId));
+    EXPECT_TRUE(IsAppInstalled(shared_module.id, shared_module.version));
+  }
+
+  void LaunchAppWithSharedModule() {
+    TestAppInfo primary_app(
+        kTestSharedModulePrimaryApp, "2.0.0",
+        std::string(kTestSharedModulePrimaryApp) + "-2.0.0.crx",
+        extensions::Manifest::TYPE_PLATFORM_APP);
+
+    std::vector<TestAppInfo> secondary_apps;
+    // Setting up FakeCWS for shared module is the same for shared module as
+    // for kiosk secondary apps.
+    TestAppInfo shared_module(kTestSharedModuleId, "1.0.0",
+                              std::string(kTestSharedModuleId) + "-1.0.0.crx",
+                              extensions::Manifest::TYPE_SHARED_MODULE);
+    secondary_apps.push_back(shared_module);
+
+    LaunchKioskWithSecondaryApps(primary_app, secondary_apps);
   }
 
  private:
@@ -1539,19 +1601,6 @@
     DISALLOW_COPY_AND_ASSIGN(KioskAppExternalUpdateWaiter);
   };
 
-  // The local cache is supposed to be initialized on chromeos device, and a
-  // ready flag file will be pre-created to mark the ready state, before chrome
-  // starts. In order for the tests to run without being on real chromeos
-  // device, we need to manually create this file.
-  void CreateAndInitializeLocalCache() {
-    base::FilePath extension_cache_dir;
-    CHECK(PathService::Get(chromeos::DIR_DEVICE_EXTENSION_LOCAL_CACHE,
-                           &extension_cache_dir));
-    base::FilePath cache_init_file = extension_cache_dir.Append(
-        extensions::LocalExtensionCache::kCacheReadyFlagFileName);
-    EXPECT_EQ(base::WriteFile(cache_init_file, "", 0), 0);
-  }
-
   // Owned by DiskMountManager.
   KioskFakeDiskMountManager* fake_disk_mount_manager_;
 
@@ -1886,9 +1935,9 @@
 // from its manifest.
 IN_PROC_BROWSER_TEST_F(KioskUpdateTest, UpdateMultiAppKioskRemoveOneApp) {
   set_test_app_id(kTestPrimaryKioskApp);
-  fake_cws()->SetUpdateCrx(
-      kTestPrimaryKioskApp,
-      std::string(kTestPrimaryKioskApp) + "-2.0.0-1app.crx", "2.0.0");
+  fake_cws()->SetUpdateCrx(kTestPrimaryKioskApp,
+                           std::string(kTestPrimaryKioskApp) + "-2.0.0.crx",
+                           "2.0.0");
   fake_cws()->SetNoUpdate(kTestSecondaryApp1);
   fake_cws()->SetNoUpdate(kTestSecondaryApp2);
 
@@ -1899,8 +1948,8 @@
 
   // Verify the secondary app kTestSecondaryApp1 is removed.
   EXPECT_EQ("2.0.0", GetInstalledAppVersion().GetString());
-  EXPECT_FALSE(IsAppInstalled(kTestSecondaryApp1));
-  EXPECT_TRUE(IsAppInstalled(kTestSecondaryApp2));
+  EXPECT_FALSE(IsAppInstalled(kTestSecondaryApp1, "1.0.0"));
+  EXPECT_TRUE(IsAppInstalled(kTestSecondaryApp2, "1.0.0"));
 }
 
 IN_PROC_BROWSER_TEST_F(KioskUpdateTest, PRE_UpdateMultiAppKioskAddOneApp) {
@@ -1911,9 +1960,9 @@
 // manifest.
 IN_PROC_BROWSER_TEST_F(KioskUpdateTest, UpdateMultiAppKioskAddOneApp) {
   set_test_app_id(kTestPrimaryKioskApp);
-  fake_cws()->SetUpdateCrx(
-      kTestPrimaryKioskApp,
-      std::string(kTestPrimaryKioskApp) + "-3.0.0-3app.crx", "3.0.0");
+  fake_cws()->SetUpdateCrx(kTestPrimaryKioskApp,
+                           std::string(kTestPrimaryKioskApp) + "-3.0.0.crx",
+                           "3.0.0");
   fake_cws()->SetNoUpdate(kTestSecondaryApp1);
   fake_cws()->SetNoUpdate(kTestSecondaryApp2);
   fake_cws()->SetUpdateCrx(kTestSecondaryApp3,
@@ -1927,9 +1976,9 @@
 
   // Verify the secondary app kTestSecondaryApp3 is installed.
   EXPECT_EQ("3.0.0", GetInstalledAppVersion().GetString());
-  EXPECT_TRUE(IsAppInstalled(kTestSecondaryApp1));
-  EXPECT_TRUE(IsAppInstalled(kTestSecondaryApp2));
-  EXPECT_TRUE(IsAppInstalled(kTestSecondaryApp3));
+  EXPECT_TRUE(IsAppInstalled(kTestSecondaryApp1, "1.0.0"));
+  EXPECT_TRUE(IsAppInstalled(kTestSecondaryApp2, "1.0.0"));
+  EXPECT_TRUE(IsAppInstalled(kTestSecondaryApp3, "1.0.0"));
 }
 
 IN_PROC_BROWSER_TEST_F(KioskUpdateTest, LaunchKioskAppWithSecondaryExtension) {
@@ -1961,27 +2010,41 @@
   WaitForAppLaunchWithOptions(false, true);
 
   // Verify the secondary app is removed.
-  EXPECT_TRUE(IsAppInstalled(kTestSharedModuleId));
-  EXPECT_FALSE(IsAppInstalled(kTestSecondaryApp1));
+  EXPECT_TRUE(IsAppInstalled(kTestSharedModuleId, "1.0.0"));
+  EXPECT_FALSE(IsAppInstalled(kTestSecondaryApp1, "1.0.0"));
 }
 
 // This simulates the stand-alone ARC kiosk app case. The primary app has a
 // shared ARC runtime but no secondary apps.
 IN_PROC_BROWSER_TEST_F(KioskUpdateTest, LaunchAppWithSharedModuleNoSecondary) {
-  TestAppInfo primary_app(
-      kTestSharedModulePrimaryApp, "2.0.0",
-      std::string(kTestSharedModulePrimaryApp) + "-2.0.0.crx",
-      extensions::Manifest::TYPE_PLATFORM_APP);
+  LaunchAppWithSharedModule();
+}
 
-  std::vector<TestAppInfo> secondary_apps;
-  // Setting up FakeCWS for shared module is the same for shared module as
-  // for kiosk secondary apps.
-  TestAppInfo shared_module(kTestSharedModuleId, "1.0.0",
-                            std::string(kTestSharedModuleId) + "-1.0.0.crx",
-                            extensions::Manifest::TYPE_SHARED_MODULE);
-  secondary_apps.push_back(shared_module);
+IN_PROC_BROWSER_TEST_F(KioskUpdateTest, PRE_LaunchAppWithUpdatedModule) {
+  LaunchAppWithSharedModule();
+  // Verify the shared module is installed with version 1.0.0.
+  EXPECT_TRUE(IsAppInstalled(kTestSharedModuleId, "1.0.0"));
+}
 
-  LaunchKioskWithSecondaryApps(primary_app, secondary_apps);
+// This simulates the case the shared module is updated to a newer version.
+// See crbug.com/555083.
+IN_PROC_BROWSER_TEST_F(KioskUpdateTest, LaunchAppWithUpdatedModule) {
+  // No update for primary app, while the shared module is set up to a new
+  // version on cws.
+  set_test_app_id(kTestSharedModulePrimaryApp);
+  fake_cws()->SetNoUpdate(kTestSharedModulePrimaryApp);
+  fake_cws()->SetUpdateCrx(kTestSharedModuleId,
+                           std::string(kTestSharedModuleId) + "-2.0.0.crx",
+                           "2.0.0");
+
+  StartUIForAppLaunch();
+  SimulateNetworkOnline();
+  LaunchApp(test_app_id(), false);
+  WaitForAppLaunchWithOptions(false, true);
+
+  // Verify the shared module is updated to the new version after primary app
+  // is launched.
+  EXPECT_TRUE(IsAppInstalled(kTestSharedModuleId, "2.0.0"));
 }
 
 IN_PROC_BROWSER_TEST_F(KioskUpdateTest,
diff --git a/chrome/browser/chromeos/login/lock/webui_screen_locker.cc b/chrome/browser/chromeos/login/lock/webui_screen_locker.cc
index 318f36b..00c7dded 100644
--- a/chrome/browser/chromeos/login/lock/webui_screen_locker.cc
+++ b/chrome/browser/chromeos/login/lock/webui_screen_locker.cc
@@ -347,7 +347,7 @@
 void WebUIScreenLocker::RenderProcessGone(base::TerminationStatus status) {
   if (browser_shutdown::GetShutdownType() == browser_shutdown::NOT_VALID &&
       status != base::TERMINATION_STATUS_NORMAL_TERMINATION) {
-    LOG(ERROR) << "Renderer crash on lock screen";
+    LOG(ERROR) << "Renderer crash on lock screen; signing out";
     Signout();
   }
 }
diff --git a/chrome/browser/chromeos/platform_keys/platform_keys_service.cc b/chrome/browser/chromeos/platform_keys/platform_keys_service.cc
index ce4e9247..d61e41f 100644
--- a/chrome/browser/chromeos/platform_keys/platform_keys_service.cc
+++ b/chrome/browser/chromeos/platform_keys/platform_keys_service.cc
@@ -4,6 +4,8 @@
 
 #include "chrome/browser/chromeos/platform_keys/platform_keys_service.h"
 
+#include <utility>
+
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/callback.h"
@@ -424,7 +426,7 @@
         }
       }
 
-      matches_.push_back(certificate.Pass());
+      matches_.push_back(std::move(certificate));
     }
     DoStep();
   }
diff --git a/chrome/browser/chromeos/printer_detector/printer_detector_unittest.cc b/chrome/browser/chromeos/printer_detector/printer_detector_unittest.cc
index e547d4a..2aa8e424 100644
--- a/chrome/browser/chromeos/printer_detector/printer_detector_unittest.cc
+++ b/chrome/browser/chromeos/printer_detector/printer_detector_unittest.cc
@@ -247,14 +247,12 @@
 
 TEST_F(PrinterDetectorAppSearchEnabledTest,
        PrinterProvider_UsbPrinters_NotFound) {
-  scoped_refptr<extensions::Extension> extension =
-      CreateTestExtension(
-          ListBuilder().Append("usb").Append("printerProvider").Pass(),
-          DictionaryBuilder().Set(
-              "filters", ListBuilder().Append(DictionaryBuilder()
-                                                  .Set("vendorId", 123)
-                                                  .Set("productId", 001))))
-          .Pass();
+  scoped_refptr<extensions::Extension> extension = CreateTestExtension(
+      ListBuilder().Append("usb").Append("printerProvider").Pass(),
+      DictionaryBuilder().Set(
+          "filters",
+          ListBuilder().Append(
+              DictionaryBuilder().Set("vendorId", 123).Set("productId", 001))));
   ASSERT_TRUE(extensions::ExtensionRegistry::Get(profile_.get())
                   ->AddEnabled(extension));
 
@@ -271,14 +269,12 @@
 
 TEST_F(PrinterDetectorAppSearchEnabledTest,
        PrinterProvider_UsbPrinters_WithProductId) {
-  scoped_refptr<extensions::Extension> extension =
-      CreateTestExtension(
-          ListBuilder().Append("usb").Append("printerProvider").Pass(),
-          DictionaryBuilder().Set(
-              "filters", ListBuilder().Append(DictionaryBuilder()
-                                                  .Set("vendorId", 123)
-                                                  .Set("productId", 456))))
-          .Pass();
+  scoped_refptr<extensions::Extension> extension = CreateTestExtension(
+      ListBuilder().Append("usb").Append("printerProvider").Pass(),
+      DictionaryBuilder().Set(
+          "filters",
+          ListBuilder().Append(
+              DictionaryBuilder().Set("vendorId", 123).Set("productId", 456))));
   ASSERT_TRUE(extensions::ExtensionRegistry::Get(profile_.get())
                   ->AddEnabled(extension));
 
@@ -295,15 +291,13 @@
 
 TEST_F(PrinterDetectorAppSearchEnabledTest,
        PrinterProvider_UsbPrinters_WithInterfaceClass) {
-  scoped_refptr<extensions::Extension> extension =
-      CreateTestExtension(
-          ListBuilder().Append("usb").Append("printerProvider").Pass(),
-          DictionaryBuilder().Set(
-              "filters",
-              ListBuilder().Append(
-                  DictionaryBuilder()
-                      .Set("vendorId", 123)
-                      .Set("interfaceClass", kPrinterInterfaceClass)))).Pass();
+  scoped_refptr<extensions::Extension> extension = CreateTestExtension(
+      ListBuilder().Append("usb").Append("printerProvider").Pass(),
+      DictionaryBuilder().Set(
+          "filters", ListBuilder().Append(
+                         DictionaryBuilder()
+                             .Set("vendorId", 123)
+                             .Set("interfaceClass", kPrinterInterfaceClass))));
   ASSERT_TRUE(extensions::ExtensionRegistry::Get(profile_.get())
                   ->AddEnabled(extension));
 
@@ -319,15 +313,13 @@
 }
 
 TEST_F(PrinterDetectorAppSearchEnabledTest, IgnoreNonPrinters) {
-  scoped_refptr<extensions::Extension> extension =
-      CreateTestExtension(
-          ListBuilder().Append("usb").Append("printerProvider").Pass(),
-          DictionaryBuilder().Set(
-              "filters",
-              ListBuilder().Append(
-                  DictionaryBuilder()
-                      .Set("vendorId", 123)
-                      .Set("interfaceClass", kPrinterInterfaceClass)))).Pass();
+  scoped_refptr<extensions::Extension> extension = CreateTestExtension(
+      ListBuilder().Append("usb").Append("printerProvider").Pass(),
+      DictionaryBuilder().Set(
+          "filters", ListBuilder().Append(
+                         DictionaryBuilder()
+                             .Set("vendorId", 123)
+                             .Set("interfaceClass", kPrinterInterfaceClass))));
   ASSERT_TRUE(extensions::ExtensionRegistry::Get(profile_.get())
                   ->AddEnabled(extension));
 
diff --git a/chrome/browser/crash_upload_list.cc b/chrome/browser/crash_upload_list.cc
index 9e30d84..95aa101 100644
--- a/chrome/browser/crash_upload_list.cc
+++ b/chrome/browser/crash_upload_list.cc
@@ -17,14 +17,14 @@
 
 scoped_refptr<CrashUploadList> CreateCrashUploadList(
     UploadList::Delegate* delegate) {
+#if defined(OS_MACOSX) || defined(OS_WIN)
+  return new CrashUploadListCrashpad(delegate,
+                                     content::BrowserThread::GetBlockingPool());
+#else
   base::FilePath crash_dir_path;
   PathService::Get(chrome::DIR_CRASH_DUMPS, &crash_dir_path);
   base::FilePath upload_log_path =
       crash_dir_path.AppendASCII(CrashUploadList::kReporterLogFilename);
-#if defined(OS_MACOSX) || defined(OS_WIN)
-  return new CrashUploadListCrashpad(delegate, upload_log_path,
-                                     content::BrowserThread::GetBlockingPool());
-#else
   return new CrashUploadList(delegate, upload_log_path,
                              content::BrowserThread::GetBlockingPool());
 #endif
diff --git a/chrome/browser/crash_upload_list_crashpad.cc b/chrome/browser/crash_upload_list_crashpad.cc
index a2a4bbdd..6d2ee263 100644
--- a/chrome/browser/crash_upload_list_crashpad.cc
+++ b/chrome/browser/crash_upload_list_crashpad.cc
@@ -6,19 +6,55 @@
 
 #include "base/threading/sequenced_worker_pool.h"
 #include "base/time/time.h"
+#include "chrome/common/chrome_constants.h"
 #include "components/crash/content/app/crashpad.h"
 
+namespace {
+
+#if defined(OS_WIN)
+typedef void (*GetUploadedReportsPointer)(
+    const crash_reporter::UploadedReport** reports,
+    size_t* report_count);
+
+void GetUploadedReportsThunk(
+    std::vector<crash_reporter::UploadedReport>* uploaded_reports) {
+  static GetUploadedReportsPointer get_uploaded_reports = []() {
+    HMODULE exe_module = GetModuleHandle(chrome::kBrowserProcessExecutableName);
+    return reinterpret_cast<GetUploadedReportsPointer>(
+        exe_module ? GetProcAddress(exe_module, "GetUploadedReportsImpl")
+                   : nullptr);
+  }();
+
+  if (get_uploaded_reports) {
+    const crash_reporter::UploadedReport* reports;
+    size_t report_count;
+    get_uploaded_reports(&reports, &report_count);
+    *uploaded_reports = std::vector<crash_reporter::UploadedReport>(
+        reports, reports + report_count);
+  }
+}
+#endif  // OS_WIN
+
+}  // namespace
+
 CrashUploadListCrashpad::CrashUploadListCrashpad(
     Delegate* delegate,
-    const base::FilePath& upload_log_path,
     const scoped_refptr<base::SequencedWorkerPool>& worker_pool)
-    : CrashUploadList(delegate, upload_log_path, worker_pool) {}
+    : CrashUploadList(delegate, base::FilePath(), worker_pool) {}
 
 CrashUploadListCrashpad::~CrashUploadListCrashpad() {}
 
 void CrashUploadListCrashpad::LoadUploadList() {
   std::vector<crash_reporter::UploadedReport> uploaded_reports;
+#if defined(OS_WIN)
+  // On Windows, we only link crash client into chrome.exe (not the dlls), and
+  // it does the registration. That means the global that holds the crash report
+  // database lives in the .exe, so we need to grab a pointer to a helper in the
+  // exe to get our uploaded reports list.
+  GetUploadedReportsThunk(&uploaded_reports);
+#else
   crash_reporter::GetUploadedReports(&uploaded_reports);
+#endif
 
   ClearUploads();
   for (const crash_reporter::UploadedReport& uploaded_report :
diff --git a/chrome/browser/crash_upload_list_crashpad.h b/chrome/browser/crash_upload_list_crashpad.h
index d884640e..2f8281b5 100644
--- a/chrome/browser/crash_upload_list_crashpad.h
+++ b/chrome/browser/crash_upload_list_crashpad.h
@@ -17,12 +17,8 @@
 // Crashpad database.
 class CrashUploadListCrashpad : public CrashUploadList {
  public:
-  // The |upload_log_path| argument is unused. It is only accepted because the
-  // base class constructor requires it, although it is entirely unused with
-  // LoadUploadList() being overridden.
   CrashUploadListCrashpad(
       Delegate* delegate,
-      const base::FilePath& upload_log_path,
       const scoped_refptr<base::SequencedWorkerPool>& worker_pool);
 
  protected:
diff --git a/chrome/browser/devtools/device/adb/adb_client_socket_browsertest.cc b/chrome/browser/devtools/device/adb/adb_client_socket_browsertest.cc
index 0f30260..e770085 100644
--- a/chrome/browser/devtools/device/adb/adb_client_socket_browsertest.cc
+++ b/chrome/browser/devtools/device/adb/adb_client_socket_browsertest.cc
@@ -134,21 +134,24 @@
   DevToolsAndroidBridge::RemoteDevices devices_;
 };
 
-IN_PROC_BROWSER_TEST_F(AdbClientSocketTest, TestFlushWithoutSize) {
+// Flaky due to failure to bind a hardcoded port. crbug.com/566057
+IN_PROC_BROWSER_TEST_F(AdbClientSocketTest, DISABLED_TestFlushWithoutSize) {
   StartMockAdbServer(FlushWithoutSize);
   StartTest();
   CheckDevices();
   StopMockAdbServer();
 }
 
-IN_PROC_BROWSER_TEST_F(AdbClientSocketTest, TestFlushWithSize) {
+// Flaky due to failure to bind a hardcoded port. crbug.com/566057
+IN_PROC_BROWSER_TEST_F(AdbClientSocketTest, DISABLED_TestFlushWithSize) {
   StartMockAdbServer(FlushWithSize);
   StartTest();
   CheckDevices();
   StopMockAdbServer();
 }
 
-IN_PROC_BROWSER_TEST_F(AdbClientSocketTest, TestFlushWithData) {
+// Flaky due to failure to bind a hardcoded port. crbug.com/566057
+IN_PROC_BROWSER_TEST_F(AdbClientSocketTest, DISABLED_TestFlushWithData) {
   StartMockAdbServer(FlushWithData);
   StartTest();
   CheckDevices();
diff --git a/chrome/browser/devtools/device/usb/android_rsa.cc b/chrome/browser/devtools/device/usb/android_rsa.cc
index eb34077..9581067 100644
--- a/chrome/browser/devtools/device/usb/android_rsa.cc
+++ b/chrome/browser/devtools/device/usb/android_rsa.cc
@@ -4,6 +4,10 @@
 
 #include "chrome/browser/devtools/device/usb/android_rsa.h"
 
+#include <stdint.h>
+
+#include <limits>
+
 #include "base/base64.h"
 #include "base/memory/scoped_ptr.h"
 #include "chrome/browser/profiles/profile.h"
@@ -27,21 +31,25 @@
     "WO5ywp0UWRiGZCkK+wOFQIDAQAB";
 
 typedef struct RSAPublicKey {
-    int len;                // Length of n[] in number of uint32
-    uint32 n0inv;           // -1 / n[0] mod 2^32
-    uint32 n[kRSANumWords];  // modulus as little endian array
-    uint32 rr[kRSANumWords]; // R^2 as little endian array
-    int exponent;           // 3 or 65537
+  int len;                    // Length of n[] in number of uint32_t
+  uint32_t n0inv;             // -1 / n[0] mod 2^32
+  uint32_t n[kRSANumWords];   // modulus as little endian array
+  uint32_t rr[kRSANumWords];  // R^2 as little endian array
+  int exponent;               // 3 or 65537
 } RSAPublicKey;
 
 // http://en.wikipedia.org/wiki/Extended_Euclidean_algorithm
 // a * x + b * y = gcd(a, b) = d
-void ExtendedEuclid(uint64 a, uint64 b, uint64 *x, uint64 *y, uint64 *d) {
-  uint64 x1 = 0, x2 = 1, y1 = 1, y2 = 0;
+void ExtendedEuclid(uint64_t a,
+                    uint64_t b,
+                    uint64_t* x,
+                    uint64_t* y,
+                    uint64_t* d) {
+  uint64_t x1 = 0, x2 = 1, y1 = 1, y2 = 0;
 
   while (b > 0) {
-    uint64 q = a / b;
-    uint64 r = a % b;
+    uint64_t q = a / b;
+    uint64_t r = a % b;
     *x = x2 - q * x1;
     *y = y2 - q * y1;
     a = b;
@@ -57,63 +65,62 @@
   *y = y2;
 }
 
-uint32 ModInverse(uint64 a, uint64 m)
-{
-  uint64 d, x, y;
+uint32_t ModInverse(uint64_t a, uint64_t m) {
+  uint64_t d, x, y;
   ExtendedEuclid(a, m, &x, &y, &d);
   if (d == 1)
-    return static_cast<uint32>(x);
+    return static_cast<uint32_t>(x);
   return 0;
 }
 
-uint32* BnNew() {
-  uint32* result = new uint32[kBigIntSize];
-  memset(result, 0, kBigIntSize * sizeof(uint32));
+uint32_t* BnNew() {
+  uint32_t* result = new uint32_t[kBigIntSize];
+  memset(result, 0, kBigIntSize * sizeof(uint32_t));
   return result;
 }
 
-void BnFree(uint32* a) {
+void BnFree(uint32_t* a) {
   delete[] a;
 }
 
-uint32* BnCopy(uint32* a) {
-  uint32* result = new uint32[kBigIntSize];
-  memcpy(result, a, kBigIntSize * sizeof(uint32));
+uint32_t* BnCopy(uint32_t* a) {
+  uint32_t* result = new uint32_t[kBigIntSize];
+  memcpy(result, a, kBigIntSize * sizeof(uint32_t));
   return result;
 }
 
-uint32* BnMul(uint32* a, uint32 b) {
-  uint32* result = BnNew();
-  uint64 carry_over = 0;
+uint32_t* BnMul(uint32_t* a, uint32_t b) {
+  uint32_t* result = BnNew();
+  uint64_t carry_over = 0;
   for (size_t i = 0; i < kBigIntSize; ++i) {
-    carry_over += static_cast<uint64>(a[i]) * b;
-    result[i] = carry_over & kuint32max;
+    carry_over += static_cast<uint64_t>(a[i]) * b;
+    result[i] = carry_over & std::numeric_limits<uint32_t>::max();
     carry_over >>= 32;
   }
   return result;
 }
 
-void BnSub(uint32* a, uint32* b) {
+void BnSub(uint32_t* a, uint32_t* b) {
   int carry_over = 0;
   for (size_t i = 0; i < kBigIntSize; ++i) {
-    int64 sub = static_cast<int64>(a[i]) - b[i] - carry_over;
+    int64_t sub = static_cast<int64_t>(a[i]) - b[i] - carry_over;
     carry_over = 0;
     if (sub < 0) {
       carry_over = 1;
       sub += 0x100000000LL;
     }
-    a[i] = static_cast<uint32>(sub);
+    a[i] = static_cast<uint32_t>(sub);
   }
 }
 
-void BnLeftShift(uint32* a, int offset) {
+void BnLeftShift(uint32_t* a, int offset) {
   for (int i = kBigIntSize - offset - 1; i >= 0; --i)
     a[i + offset] = a[i];
   for (int i = 0; i < offset; ++i)
     a[i] = 0;
 }
 
-int BnCompare(uint32* a, uint32* b) {
+int BnCompare(uint32_t* a, uint32_t* b) {
   for (int i = kBigIntSize - 1; i >= 0; --i) {
     if (a[i] > b[i])
       return 1;
@@ -123,12 +130,12 @@
   return 0;
 }
 
-uint64 BnGuess(uint32* a, uint32* b, uint64 from, uint64 to) {
+uint64_t BnGuess(uint32_t* a, uint32_t* b, uint64_t from, uint64_t to) {
   if (from + 1 >= to)
     return from;
 
-  uint64 guess = (from + to) / 2;
-  uint32* t = BnMul(b, static_cast<uint32>(guess));
+  uint64_t guess = (from + to) / 2;
+  uint32_t* t = BnMul(b, static_cast<uint32_t>(guess));
   int result = BnCompare(a, t);
   BnFree(t);
   if (result > 0)
@@ -138,7 +145,7 @@
   return guess;
 }
 
-void BnDiv(uint32* a, uint32* b, uint32** pq, uint32** pr) {
+void BnDiv(uint32_t* a, uint32_t* b, uint32_t** pq, uint32_t** pr) {
   if (BnCompare(a, b) < 0) {
     if (pq)
       *pq = BnNew();
@@ -151,18 +158,19 @@
   int ob = kBigIntSize - 1;
   for (; oa > 0 && !a[oa]; --oa) {}
   for (; ob > 0 && !b[ob]; --ob) {}
-  uint32* q = BnNew();
-  uint32* ca = BnCopy(a);
+  uint32_t* q = BnNew();
+  uint32_t* ca = BnCopy(a);
 
   int digit = a[oa] < b[ob] ? oa - ob - 1 : oa - ob;
 
   for (; digit >= 0; --digit) {
-    uint32* shifted_b = BnCopy(b);
+    uint32_t* shifted_b = BnCopy(b);
     BnLeftShift(shifted_b, digit);
-    uint32 value = static_cast<uint32>(
-        BnGuess(ca, shifted_b, 0, static_cast<uint64>(kuint32max) + 1));
+    uint32_t value = static_cast<uint32_t>(BnGuess(
+        ca, shifted_b, 0,
+        static_cast<uint64_t>(std::numeric_limits<uint32_t>::max()) + 1));
     q[digit] = value;
-    uint32* t = BnMul(shifted_b, value);
+    uint32_t* t = BnMul(shifted_b, value);
     BnSub(ca, t);
     BnFree(t);
     BnFree(shifted_b);
@@ -186,12 +194,12 @@
   std::string decoded_key;
   scoped_ptr<crypto::RSAPrivateKey> key;
   if (!encoded_key.empty() && base::Base64Decode(encoded_key, &decoded_key)) {
-    std::vector<uint8> key_info(decoded_key.begin(), decoded_key.end());
+    std::vector<uint8_t> key_info(decoded_key.begin(), decoded_key.end());
     key.reset(crypto::RSAPrivateKey::CreateFromPrivateKeyInfo(key_info));
   }
   if (!key) {
     key.reset(crypto::RSAPrivateKey::Create(2048));
-    std::vector<uint8> key_info;
+    std::vector<uint8_t> key_info;
     if (!key || !key->ExportPrivateKey(&key_info))
       return NULL;
 
@@ -204,7 +212,7 @@
 }
 
 std::string AndroidRSAPublicKey(crypto::RSAPrivateKey* key) {
-  std::vector<uint8> public_key;
+  std::vector<uint8_t> public_key;
   if (!key)
     return kDummyRSAPublicKey;
 
@@ -216,10 +224,10 @@
     return kDummyRSAPublicKey;
 
   // Skip 10 byte asn1 prefix to the modulus.
-  std::vector<uint8> pk_data(pk.data() + 10, pk.data() + pk.length());
-  uint32* n = BnNew();
+  std::vector<uint8_t> pk_data(pk.data() + 10, pk.data() + pk.length());
+  uint32_t* n = BnNew();
   for (size_t i = 0; i < kRSANumWords; ++i) {
-    uint32 t = pk_data[4 * i];
+    uint32_t t = pk_data[4 * i];
     t = t << 8;
     t += pk_data[4 * i + 1];
     t = t << 8;
@@ -228,7 +236,7 @@
     t += pk_data[4 * i + 3];
     n[kRSANumWords - i - 1] = t;
   }
-  uint64 n0 = n[0];
+  uint64_t n0 = n[0];
 
   RSAPublicKey pkey;
   pkey.len = kRSANumWords;
@@ -237,10 +245,10 @@
   if (pkey.n0inv == 0)
     return kDummyRSAPublicKey;
 
-  uint32* r = BnNew();
+  uint32_t* r = BnNew();
   r[kRSANumWords * 2] = 1;
 
-  uint32* rr;
+  uint32_t* rr;
   BnDiv(r, n, NULL, &rr);
 
   for (size_t i = 0; i < kRSANumWords; ++i) {
@@ -260,8 +268,8 @@
 
 std::string AndroidRSASign(crypto::RSAPrivateKey* key,
                            const std::string& body) {
-  std::vector<uint8> digest(body.begin(), body.end());
-  std::vector<uint8> result;
+  std::vector<uint8_t> digest(body.begin(), body.end());
+  std::vector<uint8_t> result;
   if (!crypto::SignatureCreator::Sign(key, crypto::SignatureCreator::SHA1,
                                       digest.data(), digest.size(), &result)) {
     return std::string();
diff --git a/chrome/browser/dom_distiller/profile_utils.cc b/chrome/browser/dom_distiller/profile_utils.cc
index 3eab2bb..a94ade8b 100644
--- a/chrome/browser/dom_distiller/profile_utils.cc
+++ b/chrome/browser/dom_distiller/profile_utils.cc
@@ -11,6 +11,7 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/chrome_isolated_world_ids.h"
 #include "chrome/common/chrome_switches.h"
+#include "chrome/common/features.h"
 #include "components/dom_distiller/content/browser/distiller_javascript_utils.h"
 #include "components/dom_distiller/content/browser/distiller_ui_handle.h"
 #include "components/dom_distiller/content/browser/dom_distiller_viewer_source.h"
@@ -21,9 +22,9 @@
 #include "chrome/browser/ui/webui/print_preview/print_preview_distiller.h"
 #endif  // defined(ENABLE_PRINT_PREVIEW)
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
 #include "chrome/browser/android/dom_distiller/distiller_ui_handle_android.h"
-#endif  // defined(OS_ANDROID)
+#endif  // BUILDFLAG(ANDROID_JAVA_UI)
 
 void RegisterDomDistillerViewerSource(Profile* profile) {
   bool enabled_distiller = base::CommandLine::ForCurrentProcess()->HasSwitch(
@@ -42,10 +43,10 @@
             profile, dom_distiller_service_factory);
     scoped_ptr<dom_distiller::DistillerUIHandle> ui_handle;
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
     ui_handle.reset(
         new dom_distiller::android::DistillerUIHandleAndroid());
-#endif  // defined(OS_ANDROID)
+#endif  // BUILDFLAG(ANDROID_JAVA_UI)
 
     // Set the JavaScript world ID.
     if (!dom_distiller::DistillerJavaScriptWorldIdIsSet()) {
diff --git a/chrome/browser/download/chrome_download_manager_delegate.cc b/chrome/browser/download/chrome_download_manager_delegate.cc
index 3d609fb..17f3076 100644
--- a/chrome/browser/download/chrome_download_manager_delegate.cc
+++ b/chrome/browser/download/chrome_download_manager_delegate.cc
@@ -40,6 +40,7 @@
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/scoped_tabbed_browser_displayer.h"
 #include "chrome/common/chrome_constants.h"
+#include "chrome/common/features.h"
 #include "chrome/common/pref_names.h"
 #include "components/pref_registry/pref_registry_syncable.h"
 #include "content/public/browser/download_item.h"
@@ -49,7 +50,7 @@
 #include "net/base/filename_util.h"
 #include "net/base/mime_util.h"
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
 #include "chrome/browser/android/download/chrome_download_manager_overwrite_infobar_delegate.h"
 #include "chrome/browser/infobars/infobar_service.h"
 #endif
@@ -579,7 +580,7 @@
     const base::FilePath& suggested_path,
     const DownloadTargetDeterminerDelegate::FileSelectedCallback& callback) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
   chrome::android::ChromeDownloadManagerOverwriteInfoBarDelegate::Create(
       InfoBarService::FromWebContents(download->GetWebContents()),
       suggested_path, callback);
diff --git a/chrome/browser/download/download_query.cc b/chrome/browser/download/download_query.cc
index 415b622..c6310dc 100644
--- a/chrome/browser/download/download_query.cc
+++ b/chrome/browser/download/download_query.cc
@@ -4,7 +4,10 @@
 
 #include "chrome/browser/download/download_query.h"
 
+#include <stdint.h>
+
 #include <algorithm>
+#include <limits>
 #include <string>
 #include <vector>
 
@@ -69,11 +72,11 @@
 // The next several functions are helpers for making Callbacks that access
 // DownloadItem fields.
 
-static int64 GetStartTimeMsEpoch(const DownloadItem& item) {
+static int64_t GetStartTimeMsEpoch(const DownloadItem& item) {
   return (item.GetStartTime() - base::Time::UnixEpoch()).InMilliseconds();
 }
 
-static int64 GetEndTimeMsEpoch(const DownloadItem& item) {
+static int64_t GetEndTimeMsEpoch(const DownloadItem& item) {
   return (item.GetEndTime() - base::Time::UnixEpoch()).InMilliseconds();
 }
 
@@ -239,7 +242,8 @@
   return true;
 }
 
-DownloadQuery::DownloadQuery() : limit_(kuint32max), skip_(0U) {}
+DownloadQuery::DownloadQuery()
+    : limit_(std::numeric_limits<uint32_t>::max()), skip_(0U) {}
 DownloadQuery::~DownloadQuery() {}
 
 // AddFilter() pushes a new FilterCallback to filters_. Most FilterCallbacks are
@@ -388,10 +392,11 @@
                               DownloadQuery::SortDirection direction) {
   switch (type) {
     case SORT_END_TIME:
-      sorters_.push_back(Sorter::Build<int64>(direction, &GetEndTimeMsEpoch));
+      sorters_.push_back(Sorter::Build<int64_t>(direction, &GetEndTimeMsEpoch));
       break;
     case SORT_START_TIME:
-      sorters_.push_back(Sorter::Build<int64>(direction, &GetStartTimeMsEpoch));
+      sorters_.push_back(
+          Sorter::Build<int64_t>(direction, &GetStartTimeMsEpoch));
       break;
     case SORT_URL:
       sorters_.push_back(Sorter::Build<std::string>(direction, &GetUrl));
diff --git a/chrome/browser/download/download_request_limiter.cc b/chrome/browser/download/download_request_limiter.cc
index c2d40049..4650c7a 100644
--- a/chrome/browser/download/download_request_limiter.cc
+++ b/chrome/browser/download/download_request_limiter.cc
@@ -11,6 +11,7 @@
 #include "chrome/browser/infobars/infobar_service.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/tab_contents/tab_util.h"
+#include "chrome/common/features.h"
 #include "components/content_settings/core/browser/host_content_settings_map.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_thread.h"
@@ -24,7 +25,7 @@
 #include "content/public/browser/web_contents_delegate.h"
 #include "url/gurl.h"
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
 #include "chrome/browser/download/download_request_infobar_delegate_android.h"
 #else
 #include "chrome/browser/download/download_permission_request.h"
@@ -99,7 +100,7 @@
     return;
   }
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
   bool promptable = InfoBarService::FromWebContents(web_contents()) != nullptr;
 #else
   bool promptable =
@@ -133,7 +134,7 @@
   if (is_showing_prompt())
     return;
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
   DownloadRequestInfoBarDelegateAndroid::Create(
       InfoBarService::FromWebContents(web_contents_), factory_.GetWeakPtr());
 #else
diff --git a/chrome/browser/download/download_resource_throttle_unittest.cc b/chrome/browser/download/download_resource_throttle_unittest.cc
index dd4365d..8c320f7 100644
--- a/chrome/browser/download/download_resource_throttle_unittest.cc
+++ b/chrome/browser/download/download_resource_throttle_unittest.cc
@@ -7,6 +7,7 @@
 #include "chrome/browser/download/download_request_limiter.h"
 #include "chrome/browser/download/download_resource_throttle.h"
 #include "chrome/browser/tab_contents/tab_util.h"
+#include "chrome/common/features.h"
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/render_process_host.h"
@@ -18,7 +19,7 @@
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
 #include "chrome/browser/android/download/mock_download_controller_android.h"
 #endif
 
@@ -62,7 +63,7 @@
     ChromeRenderViewHostTestHarness::SetUp();
     web_contents()->SetDelegate(&delegate_);
     run_loop_.reset(new base::RunLoop());
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
     content::DownloadControllerAndroid::SetDownloadControllerAndroid(
         &download_controller_);
 #endif
@@ -71,7 +72,7 @@
   void TearDown() override {
     content::BrowserThread::DeleteSoon(content::BrowserThread::IO, FROM_HERE,
                                        throttle_);
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
     content::DownloadControllerAndroid::SetDownloadControllerAndroid(nullptr);
 #endif
     ChromeRenderViewHostTestHarness::TearDown();
@@ -104,7 +105,7 @@
   scoped_refptr<DownloadRequestLimiter> limiter_;
   ::testing::NiceMock<MockResourceController> resource_controller_;
   scoped_ptr<base::RunLoop> run_loop_;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
   chrome::android::MockDownloadControllerAndroid download_controller_;
 #endif
 };
@@ -115,7 +116,7 @@
   StartThrottle();
 }
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
 TEST_F(DownloadResourceThrottleTest, DownloadWithFailedFileAcecssRequest) {
   content::DownloadControllerAndroid::Get()
       ->SetApproveFileAccessRequestForTesting(false);
diff --git a/chrome/browser/engagement/site_engagement_service.cc b/chrome/browser/engagement/site_engagement_service.cc
index b875eb6..52cbaf0 100644
--- a/chrome/browser/engagement/site_engagement_service.cc
+++ b/chrome/browser/engagement/site_engagement_service.cc
@@ -15,6 +15,7 @@
 #include "base/time/clock.h"
 #include "base/time/default_clock.h"
 #include "base/values.h"
+#include "chrome/browser/banners/app_banner_settings_helper.h"
 #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
 #include "chrome/browser/engagement/site_engagement_eviction_policy.h"
 #include "chrome/browser/engagement/site_engagement_helper.h"
@@ -281,7 +282,8 @@
   // return true immediately.
   if (base::CommandLine::ForCurrentProcess()->HasSwitch(
           switches::kEnableSiteEngagementService) ||
-      SiteEngagementEvictionPolicy::IsEnabled()) {
+      SiteEngagementEvictionPolicy::IsEnabled() ||
+      AppBannerSettingsHelper::ShouldUseSiteEngagementScore()) {
     return true;
   }
 
diff --git a/chrome/browser/engagement/site_engagement_service.h b/chrome/browser/engagement/site_engagement_service.h
index 6489fff..46bf9896 100644
--- a/chrome/browser/engagement/site_engagement_service.h
+++ b/chrome/browser/engagement/site_engagement_service.h
@@ -180,6 +180,7 @@
   FRIEND_TEST_ALL_PREFIXES(SiteEngagementServiceTest, GetTotalUserInputPoints);
   FRIEND_TEST_ALL_PREFIXES(SiteEngagementServiceTest,
                            CleanupOriginsOnHistoryDeletion);
+  FRIEND_TEST_ALL_PREFIXES(AppBannerSettingsHelperTest, SiteEngagementTrigger);
 
   // Only used in tests.
   SiteEngagementService(Profile* profile, scoped_ptr<base::Clock> clock);
diff --git a/chrome/browser/extensions/extension_action.cc b/chrome/browser/extensions/extension_action.cc
index c6033e53f..3b2225452 100644
--- a/chrome/browser/extensions/extension_action.cc
+++ b/chrome/browser/extensions/extension_action.cc
@@ -8,6 +8,7 @@
 
 #include "base/base64.h"
 #include "base/logging.h"
+#include "base/strings/string_number_conversions.h"
 #include "extensions/browser/extension_icon_image.h"
 #include "extensions/browser/extension_icon_placeholder.h"
 #include "extensions/common/constants.h"
@@ -22,6 +23,7 @@
 #include "third_party/skia/include/core/SkCanvas.h"
 #include "third_party/skia/include/core/SkPaint.h"
 #include "third_party/skia/include/effects/SkGradientShader.h"
+#include "ui/base/resource/material_design/material_design_controller.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/gfx/animation/animation_delegate.h"
 #include "ui/gfx/canvas.h"
@@ -43,23 +45,6 @@
       IDR_EXTENSIONS_FAVICON);
 }
 
-// Given the extension action type, returns the size the extension action icon
-// should have. The icon should be square, so only one dimension is
-// returned.
-int GetIconSizeForType(extensions::ActionInfo::Type type) {
-  switch (type) {
-    case extensions::ActionInfo::TYPE_BROWSER:
-    case extensions::ActionInfo::TYPE_PAGE:
-    case extensions::ActionInfo::TYPE_SYSTEM_INDICATOR:
-      // TODO(dewittj) Report the actual icon size of the system
-      // indicator.
-      return extension_misc::EXTENSION_ICON_ACTION;
-    default:
-      NOTREACHED();
-      return 0;
-  }
-}
-
 class GetAttentionImageSource : public gfx::ImageSkiaSource {
  public:
   explicit GetAttentionImageSource(const gfx::ImageSkia& icon)
@@ -86,9 +71,6 @@
   ui::ScaleFactor scale;
 };
 
-const IconRepresentationInfo kIconSizes[] = {{"19", ui::SCALE_FACTOR_100P},
-                                             {"38", ui::SCALE_FACTOR_200P}};
-
 template <class T>
 bool HasValue(const std::map<int, T>& map, int tab_id) {
   return map.find(tab_id) != map.end();
@@ -96,9 +78,13 @@
 
 }  // namespace
 
+extension_misc::ExtensionIcons ExtensionAction::ActionIconSize() {
+  return ui::MaterialDesignController::IsModeMaterial()
+             ? extension_misc::EXTENSION_ICON_BITTY
+             : extension_misc::EXTENSION_ICON_ACTION;
+}
+
 const int ExtensionAction::kDefaultTabId = -1;
-const int ExtensionAction::kPageActionIconMaxSize =
-    extension_misc::EXTENSION_ICON_ACTION;
 
 ExtensionAction::ExtensionAction(const extensions::Extension& extension,
                                  extensions::ActionInfo::Type action_type,
@@ -140,14 +126,18 @@
 bool ExtensionAction::ParseIconFromCanvasDictionary(
     const base::DictionaryValue& dict,
     gfx::ImageSkia* icon) {
-  // Try to extract an icon for each known scale.
-  for (size_t i = 0; i < arraysize(kIconSizes); i++) {
+  for (base::DictionaryValue::Iterator iter(dict); !iter.IsAtEnd();
+       iter.Advance()) {
+    int icon_size = 0;
+    if (!base::StringToInt(iter.key(), &icon_size))
+      continue;
+
     const base::BinaryValue* image_data;
     std::string binary_string64;
     IPC::Message pickle;
-    if (dict.GetBinary(kIconSizes[i].size_string, &image_data)) {
+    if (iter.value().GetAsBinary(&image_data)) {
       pickle = IPC::Message(image_data->GetBuffer(), image_data->GetSize());
-    } else if (dict.GetString(kIconSizes[i].size_string, &binary_string64)) {
+    } else if (iter.value().GetAsString(&binary_string64)) {
       std::string binary_string;
       if (!base::Base64Decode(binary_string64, &binary_string))
         return false;
@@ -155,12 +145,13 @@
     } else {
       continue;
     }
-    base::PickleIterator iter(pickle);
+    base::PickleIterator pickle_iter(pickle);
     SkBitmap bitmap;
-    if (!IPC::ReadParam(&pickle, &iter, &bitmap))
+    if (!IPC::ReadParam(&pickle, &pickle_iter, &bitmap))
       return false;
     CHECK(!bitmap.isNull());
-    float scale = ui::GetScaleForScaleFactor(kIconSizes[i].scale);
+    float scale =
+        static_cast<float>(icon_size) / ExtensionAction::ActionIconSize();
     icon->AddRepresentation(gfx::ImageSkiaRep(bitmap, scale));
   }
   return true;
@@ -240,12 +231,8 @@
     content::BrowserContext* browser_context) {
   if (default_icon_ && !default_icon_image_) {
     default_icon_image_.reset(new extensions::IconImage(
-        browser_context,
-        &extension,
-        *default_icon(),
-        GetIconSizeForType(action_type_),
-        *GetDefaultIcon().ToImageSkia(),
-        nullptr));
+        browser_context, &extension, *default_icon(), ActionIconSize(),
+        *GetDefaultIcon().ToImageSkia(), nullptr));
   }
   return default_icon_image_.get();
 }
@@ -262,8 +249,8 @@
     // default (puzzle piece).
     if (extensions::FeatureSwitch::extension_action_redesign()->IsEnabled()) {
       placeholder_icon_image_ =
-          extensions::ExtensionIconPlaceholder::CreateImage(
-              extension_misc::EXTENSION_ICON_ACTION, extension_name_);
+          extensions::ExtensionIconPlaceholder::CreateImage(ActionIconSize(),
+                                                            extension_name_);
     } else {
       placeholder_icon_image_ = GetDefaultIcon();
     }
@@ -316,32 +303,14 @@
   set_id(manifest_data.id);
 
   // Initialize the specified icon set.
-  if (!manifest_data.default_icon.empty())
+  if (!manifest_data.default_icon.empty()) {
     default_icon_.reset(new ExtensionIconSet(manifest_data.default_icon));
-
-  const ExtensionIconSet& extension_icons =
-      extensions::IconsInfo::GetIcons(&extension);
-  // Look for any other icons.
-  std::string largest_icon = extension_icons.Get(
-      extension_misc::EXTENSION_ICON_GIGANTOR, ExtensionIconSet::MATCH_SMALLER);
-
-  if (!largest_icon.empty()) {
-    // We found an icon to use, so create an icon set if one doesn't exist.
-    if (!default_icon_)
-      default_icon_.reset(new ExtensionIconSet());
-    int largest_icon_size = extension_icons.GetIconSizeFromPath(largest_icon);
-    // Replace any missing extension action icons with the largest icon
-    // retrieved from |extension|'s manifest so long as the largest icon is
-    // larger than the current key.
-    for (int i = extension_misc::kNumExtensionActionIconSizes - 1; i >= 0;
-         --i) {
-      int size = extension_misc::kExtensionActionIconSizes[i].size;
-      if (default_icon_->Get(size, ExtensionIconSet::MATCH_BIGGER).empty() &&
-          largest_icon_size > size) {
-        default_icon_->Add(size, largest_icon);
-        break;
-      }
-    }
+  } else {
+    // Fall back to the product icons if no action icon exists.
+    const ExtensionIconSet& product_icons =
+        extensions::IconsInfo::GetIcons(&extension);
+    if (!product_icons.empty())
+      default_icon_.reset(new ExtensionIconSet(product_icons));
   }
 }
 
@@ -354,7 +323,7 @@
   // If there is a default icon, the icon width will be set depending on our
   // action type.
   if (default_icon_)
-    return GetIconSizeForType(action_type());
+    return ActionIconSize();
 
   // If no icon has been set and there is no default icon, we need favicon
   // width.
diff --git a/chrome/browser/extensions/extension_action.h b/chrome/browser/extensions/extension_action.h
index ff29481..866c1e4 100644
--- a/chrome/browser/extensions/extension_action.h
+++ b/chrome/browser/extensions/extension_action.h
@@ -12,6 +12,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/stl_util.h"
 #include "chrome/common/extensions/api/extension_action/action_info.h"
+#include "extensions/common/constants.h"
 #include "third_party/skia/include/core/SkColor.h"
 #include "ui/gfx/image/image.h"
 
@@ -47,13 +48,12 @@
     // the UI.
   };
 
+  static extension_misc::ExtensionIcons ActionIconSize();
+
   // Use this ID to indicate the default state for properties that take a tab_id
   // parameter.
   static const int kDefaultTabId;
 
-  // Max size (both dimensions) for page actions.
-  static const int kPageActionIconMaxSize;
-
   ExtensionAction(const extensions::Extension& extension,
                   extensions::ActionInfo::Type action_type,
                   const extensions::ActionInfo& manifest_data);
diff --git a/chrome/browser/extensions/extension_action_manager_unittest.cc b/chrome/browser/extensions/extension_action_manager_unittest.cc
index b29328e..d040762 100644
--- a/chrome/browser/extensions/extension_action_manager_unittest.cc
+++ b/chrome/browser/extensions/extension_action_manager_unittest.cc
@@ -98,9 +98,9 @@
                                             const ExtensionAction& action,
                                             int action_key) {
   return action.default_icon()->Get(action_key,
-                                    ExtensionIconSet::MATCH_EXACTLY) ==
-      IconsInfo::GetIcons(&extension).Get(extension_key,
-                                          ExtensionIconSet::MATCH_EXACTLY);
+                                    ExtensionIconSet::MATCH_BIGGER) ==
+         IconsInfo::GetIcons(&extension)
+             .Get(extension_key, ExtensionIconSet::MATCH_EXACTLY);
 }
 
 ExtensionAction* ExtensionActionManagerTest::GetAction(
@@ -127,7 +127,7 @@
   ASSERT_TRUE(action);
 
   ASSERT_TRUE(TitlesMatch(*extension.get(), *action));
-  ASSERT_TRUE(IconsMatch(*extension.get(), 128, *action, 38));
+  ASSERT_TRUE(IconsMatch(*extension.get(), 48, *action, 38));
 
   // Test that the action's missing default_icons are not replaced with smaller
   // icons.
diff --git a/chrome/browser/extensions/extension_action_storage_manager.cc b/chrome/browser/extensions/extension_action_storage_manager.cc
index a7de1e6..401e077 100644
--- a/chrome/browser/extensions/extension_action_storage_manager.cc
+++ b/chrome/browser/extensions/extension_action_storage_manager.cc
@@ -75,8 +75,7 @@
 }
 
 // Conversion function for reading/writing to storage.
-std::string RepresentationToString(const gfx::ImageSkia& image, float scale) {
-  SkBitmap bitmap = image.GetRepresentation(scale).sk_bitmap();
+std::string BitmapToString(const SkBitmap& bitmap) {
   SkAutoLockPixels lock_image(bitmap);
   std::vector<unsigned char> data;
   bool success = gfx::PNGCodec::EncodeBGRASkBitmap(bitmap, false, &data);
@@ -95,9 +94,6 @@
                           ExtensionAction* action) {
   const int kDefaultTabId = ExtensionAction::kDefaultTabId;
   std::string str_value;
-  int int_value;
-  SkBitmap bitmap;
-  gfx::ImageSkia icon;
 
   // For each value, don't set it if it has been modified already.
   if (dict->GetString(kPopupUrlStorageKey, &str_value) &&
@@ -121,9 +117,11 @@
       !action->HasBadgeTextColor(kDefaultTabId)) {
     action->SetBadgeTextColor(kDefaultTabId, RawStringToSkColor(str_value));
   }
-  if (dict->GetInteger(kAppearanceStorageKey, &int_value) &&
+
+  int appearance_storage = 0;
+  if (dict->GetInteger(kAppearanceStorageKey, &appearance_storage) &&
       !action->HasIsVisible(kDefaultTabId)) {
-    switch (int_value) {
+    switch (appearance_storage) {
       case INVISIBLE:
       case OBSOLETE_WANTS_ATTENTION:
         action->SetIsVisible(kDefaultTabId, false);
@@ -137,13 +135,18 @@
   const base::DictionaryValue* icon_value = NULL;
   if (dict->GetDictionary(kIconStorageKey, &icon_value) &&
       !action->HasIcon(kDefaultTabId)) {
-    for (size_t i = 0; i < extension_misc::kNumExtensionActionIconSizes; i++) {
-      const extension_misc::IconRepresentationInfo& icon_info =
-          extension_misc::kExtensionActionIconSizes[i];
-      if (icon_value->GetString(icon_info.size_string, &str_value) &&
-          StringToSkBitmap(str_value, &bitmap)) {
+    gfx::ImageSkia icon;
+    SkBitmap bitmap;
+    for (base::DictionaryValue::Iterator iter(*icon_value); !iter.IsAtEnd();
+         iter.Advance()) {
+      int icon_size = 0;
+      std::string icon_string;
+      if (base::StringToInt(iter.key(), &icon_size) &&
+          iter.value().GetAsString(&icon_string) &&
+          StringToSkBitmap(icon_string, &bitmap)) {
         CHECK(!bitmap.isNull());
-        float scale = ui::GetScaleForScaleFactor(icon_info.scale);
+        float scale =
+            static_cast<float>(icon_size) / ExtensionAction::ActionIconSize();
         icon.AddRepresentation(gfx::ImageSkiaRep(bitmap, scale));
       }
     }
@@ -173,18 +176,15 @@
       action->GetExplicitlySetIcon(kDefaultTabId).AsImageSkia();
   if (!icon.isNull()) {
     scoped_ptr<base::DictionaryValue> icon_value(new base::DictionaryValue());
-    for (size_t i = 0; i < extension_misc::kNumExtensionActionIconSizes; i++) {
-      const extension_misc::IconRepresentationInfo& icon_info =
-          extension_misc::kExtensionActionIconSizes[i];
-      float scale = ui::GetScaleForScaleFactor(icon_info.scale);
-      if (icon.HasRepresentation(scale)) {
-        icon_value->SetString(icon_info.size_string,
-                              RepresentationToString(icon, scale));
-      }
+    std::vector<gfx::ImageSkiaRep> image_reps = icon.image_reps();
+    for (const gfx::ImageSkiaRep& rep : image_reps) {
+      int size = static_cast<int>(rep.scale() * icon.width());
+      std::string size_string = base::IntToString(size);
+      icon_value->SetString(size_string, BitmapToString(rep.sk_bitmap()));
     }
-    dict->Set(kIconStorageKey, icon_value.release());
+    dict->Set(kIconStorageKey, icon_value.Pass());
   }
-  return dict.Pass();
+  return dict;
 }
 
 }  // namespace
diff --git a/chrome/browser/extensions/install_verifier.cc b/chrome/browser/extensions/install_verifier.cc
index b5bdbd7..2ede600 100644
--- a/chrome/browser/extensions/install_verifier.cc
+++ b/chrome/browser/extensions/install_verifier.cc
@@ -67,7 +67,11 @@
     return ENFORCE_STRICT;
   }
 
+#if defined(OS_WIN)
+  VerifyStatus default_status = ENFORCE;
+#else
   VerifyStatus default_status = NONE;
+#endif
 
   if (group == "EnforceStrict")
     return ENFORCE_STRICT;
diff --git a/chrome/browser/extensions/service_worker_apitest.cc b/chrome/browser/extensions/service_worker_apitest.cc
index 9870d41..0d7a9a97 100644
--- a/chrome/browser/extensions/service_worker_apitest.cc
+++ b/chrome/browser/extensions/service_worker_apitest.cc
@@ -171,7 +171,8 @@
 
   // ExtensionApiTest overrides.
   void SetUpCommandLine(base::CommandLine* command_line) override {
-    command_line->AppendSwitch(switches::kEnablePushMessagePayload);
+    command_line->AppendSwitch(
+        switches::kEnableExperimentalWebPlatformFeatures);
     ServiceWorkerTest::SetUpCommandLine(command_line);
   }
   void SetUpOnMainThread() override {
diff --git a/chrome/browser/geolocation/geolocation_permission_context_factory.cc b/chrome/browser/geolocation/geolocation_permission_context_factory.cc
index 27742b6..2f9625b 100644
--- a/chrome/browser/geolocation/geolocation_permission_context_factory.cc
+++ b/chrome/browser/geolocation/geolocation_permission_context_factory.cc
@@ -6,10 +6,11 @@
 
 #include "chrome/browser/profiles/incognito_helpers.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/common/features.h"
 #include "chrome/common/pref_names.h"
 #include "components/keyed_service/content/browser_context_dependency_manager.h"
 #include "components/pref_registry/pref_registry_syncable.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
 #include "chrome/browser/geolocation/geolocation_permission_context_android.h"
 #else
 #include "chrome/browser/geolocation/geolocation_permission_context.h"
@@ -29,7 +30,7 @@
   return base::Singleton<GeolocationPermissionContextFactory>::get();
 }
 
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(ANDROID_JAVA_UI)
 GeolocationPermissionContextFactory::GeolocationPermissionContextFactory()
     : PermissionContextFactoryBase(
           "GeolocationPermissionContext",
@@ -50,7 +51,7 @@
 KeyedService*
 GeolocationPermissionContextFactory::BuildServiceInstanceFor(
     content::BrowserContext* profile) const {
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(ANDROID_JAVA_UI)
   return new GeolocationPermissionContext(static_cast<Profile*>(profile));
 #else
   return new GeolocationPermissionContextAndroid(
@@ -60,7 +61,7 @@
 
 void GeolocationPermissionContextFactory::RegisterProfilePrefs(
     user_prefs::PrefRegistrySyncable* registry) {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
   registry->RegisterBooleanPref(prefs::kGeolocationEnabled, true);
 #endif
 }
diff --git a/chrome/browser/geolocation/geolocation_permission_context_unittest.cc b/chrome/browser/geolocation/geolocation_permission_context_unittest.cc
index e33acba..42273ac 100644
--- a/chrome/browser/geolocation/geolocation_permission_context_unittest.cc
+++ b/chrome/browser/geolocation/geolocation_permission_context_unittest.cc
@@ -25,6 +25,7 @@
 #include "chrome/browser/permissions/permission_request_id.h"
 #include "chrome/browser/ui/website_settings/permission_bubble_request.h"
 #include "chrome/common/chrome_switches.h"
+#include "chrome/common/features.h"
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/content_settings/core/browser/host_content_settings_map.h"
@@ -44,7 +45,7 @@
 #include "content/public/test/web_contents_tester.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
 #include "base/prefs/pref_service.h"
 #include "chrome/browser/android/mock_location_settings.h"
 #include "chrome/browser/geolocation/geolocation_permission_context_android.h"
@@ -143,7 +144,7 @@
   void AddNewTab(const GURL& url);
   void CheckTabContentsState(const GURL& requesting_frame,
                              ContentSetting expected_content_setting);
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(ANDROID_JAVA_UI)
   size_t GetBubblesQueueSize(PermissionBubbleManager* manager);
   void AcceptBubble(PermissionBubbleManager* manager);
   void DenyBubble(PermissionBubbleManager* manager);
@@ -239,7 +240,7 @@
 #if defined(ENABLE_EXTENSIONS)
   extensions::SetViewType(new_tab, extensions::VIEW_TYPE_TAB_CONTENTS);
 #endif
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
   InfoBarService::CreateForWebContents(new_tab);
 #else
   PermissionBubbleManager::CreateForWebContents(new_tab);
@@ -279,7 +280,7 @@
   TabSpecificContentSettings::CreateForWebContents(web_contents());
   geolocation_permission_context_ =
       GeolocationPermissionContextFactory::GetForProfile(profile());
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
   static_cast<GeolocationPermissionContextAndroid*>(
       geolocation_permission_context_)
       ->SetLocationSettingsForTesting(
@@ -299,7 +300,7 @@
   ChromeRenderViewHostTestHarness::TearDown();
 }
 
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(ANDROID_JAVA_UI)
 size_t GeolocationPermissionContextTests::GetBubblesQueueSize(
     PermissionBubbleManager* manager) {
   return manager->requests_.size();
@@ -328,7 +329,7 @@
 
 void GeolocationPermissionContextTests::BubbleManagerDocumentLoadCompleted(
     content::WebContents* web_contents) {
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(ANDROID_JAVA_UI)
   PermissionBubbleManager::FromWebContents(web_contents)->
       DocumentOnLoadCompletedInMainFrame();
 #endif
@@ -344,7 +345,7 @@
 }
 
 size_t GeolocationPermissionContextTests::GetNumberOfPrompts() {
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(ANDROID_JAVA_UI)
   PermissionBubbleManager* manager =
       PermissionBubbleManager::FromWebContents(web_contents());
   return GetBubblesQueueSize(manager);
@@ -354,7 +355,7 @@
 }
 
 void GeolocationPermissionContextTests::AcceptPrompt() {
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(ANDROID_JAVA_UI)
   PermissionBubbleManager* manager =
       PermissionBubbleManager::FromWebContents(web_contents());
   AcceptBubble(manager);
@@ -367,7 +368,7 @@
 }
 
 base::string16 GeolocationPermissionContextTests::GetPromptText() {
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(ANDROID_JAVA_UI)
   PermissionBubbleManager* manager =
       PermissionBubbleManager::FromWebContents(web_contents());
   return manager->requests_.front()->GetMessageText();
@@ -392,7 +393,7 @@
   ASSERT_EQ(1U, GetNumberOfPrompts());
 }
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
 TEST_F(GeolocationPermissionContextTests, SinglePermissionInfobar) {
   GURL requesting_frame("http://www.example.com/geolocation");
   NavigateAndCommit(requesting_frame);
@@ -490,7 +491,7 @@
   CheckTabContentsState(requesting_frame_0, CONTENT_SETTING_ALLOW);
   CheckPermissionMessageSent(0, true);
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
   infobars::InfoBar* infobar_0 = infobar_service()->infobar_at(0);
   infobar_service()->RemoveInfoBar(infobar_0);
   EXPECT_EQ(1U, closed_infobar_tracker_.size());
@@ -506,7 +507,7 @@
   EXPECT_NE(text_0, text_1);
 
   // Cancel (block) this frame.
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(ANDROID_JAVA_UI)
   PermissionBubbleManager* manager =
       PermissionBubbleManager::FromWebContents(web_contents());
   DenyBubble(manager);
@@ -536,7 +537,7 @@
 
   // Check permission is requested.
   ASSERT_EQ(0U, GetNumberOfPrompts());
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
   const bool user_gesture = false;
 #else
   const bool user_gesture = true;
@@ -556,7 +557,7 @@
   CheckPermissionMessageSent(0, true);
 
   // Cleanup.
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
   infobars::InfoBar* infobar = infobar_service()->infobar_at(0);
   infobar_service()->RemoveInfoBar(infobar);
   EXPECT_EQ(1U, closed_infobar_tracker_.size());
@@ -566,7 +567,7 @@
 
 // TODO(felt): The bubble is rejecting file:// permission requests.
 // Fix and enable this test. crbug.com/444047
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
 #define MAYBE_PermissionForFileScheme PermissionForFileScheme
 #else
 #define MAYBE_PermissionForFileScheme DISABLED_PermissionForFileScheme
@@ -618,7 +619,7 @@
   ASSERT_FALSE(text_0.empty());
 
   // Simulate the frame going away; the request should be removed.
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(ANDROID_JAVA_UI)
   PermissionBubbleManager* manager =
       PermissionBubbleManager::FromWebContents(web_contents());
   CloseBubble(manager);
@@ -667,7 +668,7 @@
   BubbleManagerDocumentLoadCompleted();
   BubbleManagerDocumentLoadCompleted(extra_tabs_[0]);
   BubbleManagerDocumentLoadCompleted(extra_tabs_[1]);
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(ANDROID_JAVA_UI)
   PermissionBubbleManager* manager_a0 =
       PermissionBubbleManager::FromWebContents(web_contents());
   PermissionBubbleManager* manager_b =
@@ -684,7 +685,7 @@
   RequestGeolocationPermission(
       extra_tabs_[1], RequestIDForTab(1, 0), url_a, true);
   ASSERT_EQ(1U, GetNumberOfPrompts());  // For A0.
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(ANDROID_JAVA_UI)
   ASSERT_EQ(1U, GetBubblesQueueSize(manager_b));
   ASSERT_EQ(1U, GetBubblesQueueSize(manager_a1));
 #else
@@ -693,7 +694,7 @@
 #endif
 
   // Accept the permission in tab A0.
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(ANDROID_JAVA_UI)
   AcceptBubble(manager_a0);
 #else
   infobars::InfoBar* infobar_a0 = infobar_service()->infobar_at(0);
@@ -710,7 +711,7 @@
   // disappear. It does not cause the bubble to disappear: crbug.com/443013.
   // TODO(felt): Update this test when the bubble's behavior is changed.
   // Either way, tab B should still have a pending permission request.
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(ANDROID_JAVA_UI)
   ASSERT_EQ(1U, GetBubblesQueueSize(manager_a1));
   ASSERT_EQ(1U, GetBubblesQueueSize(manager_b));
 #else
@@ -724,7 +725,7 @@
   GURL url_b("http://www.example-2.com/geolocation");
   NavigateAndCommit(url_a);  // Tab A0.
   AddNewTab(url_a);          // Tab A1.
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(ANDROID_JAVA_UI)
   BubbleManagerDocumentLoadCompleted();
   BubbleManagerDocumentLoadCompleted(extra_tabs_[0]);
   PermissionBubbleManager* manager_a0 =
@@ -741,7 +742,7 @@
       extra_tabs_[0], RequestIDForTab(0, 0), url_a, true);
   RequestGeolocationPermission(
       extra_tabs_[0], RequestIDForTab(0, 1), url_b, true);
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(ANDROID_JAVA_UI)
   ASSERT_EQ(1U, GetBubblesQueueSize(manager_a0));
   ASSERT_EQ(1U, GetBubblesQueueSize(manager_a1));
 #else
@@ -750,7 +751,7 @@
 #endif
 
   // Accept the first request in tab A1.
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(ANDROID_JAVA_UI)
   AcceptBubble(manager_a1);
 #else
   infobars::InfoBar* infobar_a1 = infobar_service_for_tab(0)->infobar_at(0);
@@ -767,7 +768,7 @@
   // Because they're the same origin, this will cause tab A0's infobar to
   // disappear. It does not cause the bubble to disappear: crbug.com/443013.
   // TODO(felt): Update this test when the bubble's behavior is changed.
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(ANDROID_JAVA_UI)
   EXPECT_EQ(1U, GetBubblesQueueSize(manager_a0));
 #else
   EXPECT_EQ(0U, infobar_service()->infobar_count());
@@ -775,14 +776,14 @@
 #endif
 
   // The second request should now be visible in tab A1.
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(ANDROID_JAVA_UI)
   ASSERT_EQ(1U, GetBubblesQueueSize(manager_a1));
 #else
   ASSERT_EQ(1U, infobar_service_for_tab(0)->infobar_count());
 #endif
 
   // Accept the second request and check that it's gone.
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(ANDROID_JAVA_UI)
   AcceptBubble(manager_a1);
   EXPECT_EQ(0U, GetBubblesQueueSize(manager_a1));
 #else
@@ -817,7 +818,7 @@
   ASSERT_EQ(1U, GetNumberOfPrompts());
 
   // Delete the tab contents.
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
   infobars::InfoBar* infobar = infobar_service()->infobar_at(0);
   DeleteContents();
   ASSERT_EQ(1U, closed_infobar_tracker_.size());
@@ -915,7 +916,7 @@
 
   // Accept the first frame.
   AcceptPrompt();
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
   infobar_service()->RemoveInfoBar(infobar_service()->infobar_at(0));
 #endif
   CheckTabContentsState(requesting_frame_0, CONTENT_SETTING_ALLOW);
@@ -940,7 +941,7 @@
   AcceptPrompt();
   CheckTabContentsState(requesting_frame_1, CONTENT_SETTING_ALLOW);
   CheckPermissionMessageSent(1, true);
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
   infobar_service()->RemoveInfoBar(infobar_service()->infobar_at(0));
 #endif
 
diff --git a/chrome/browser/history/chrome_history_backend_client.cc b/chrome/browser/history/chrome_history_backend_client.cc
index 1d0e841..595994b 100644
--- a/chrome/browser/history/chrome_history_backend_client.cc
+++ b/chrome/browser/history/chrome_history_backend_client.cc
@@ -5,18 +5,19 @@
 #include "chrome/browser/history/chrome_history_backend_client.h"
 
 #include "chrome/common/channel_info.h"
+#include "chrome/common/features.h"
 #include "components/bookmarks/browser/bookmark_model.h"
 #include "components/version_info/version_info.h"
 #include "url/gurl.h"
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
 #include "base/files/file_path.h"
 #include "base/logging.h"
 #include "chrome/browser/history/android/android_provider_backend.h"
 #include "components/history/core/browser/history_backend.h"
 #endif
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
 namespace {
 const base::FilePath::CharType kAndroidCacheFilename[] =
     FILE_PATH_LITERAL("AndroidCache");
@@ -70,7 +71,7 @@
          channel != version_info::Channel::BETA;
 }
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
 void ChromeHistoryBackendClient::OnHistoryBackendInitialized(
     history::HistoryBackend* history_backend,
     history::HistoryDatabase* history_database,
@@ -91,4 +92,4 @@
     const base::FilePath& history_dir) {
   sql::Connection::Delete(history_dir.Append(kAndroidCacheFilename));
 }
-#endif  // defined(OS_ANDROID)
+#endif  // BUILDFLAG(ANDROID_JAVA_UI)
diff --git a/chrome/browser/importer/importer_list.cc b/chrome/browser/importer/importer_list.cc
index e006503..be62f423 100644
--- a/chrome/browser/importer/importer_list.cc
+++ b/chrome/browser/importer/importer_list.cc
@@ -29,30 +29,29 @@
 namespace {
 
 #if defined(OS_WIN)
-void DetectIEProfiles(std::vector<importer::SourceProfile*>* profiles) {
+void DetectIEProfiles(std::vector<importer::SourceProfile>* profiles) {
   DCHECK_CURRENTLY_ON(BrowserThread::FILE);
   // IE always exists and doesn't have multiple profiles.
-  importer::SourceProfile* ie = new importer::SourceProfile;
-  ie->importer_name = l10n_util::GetStringUTF16(IDS_IMPORT_FROM_IE);
-  ie->importer_type = importer::TYPE_IE;
-  ie->source_path.clear();
-  ie->app_path.clear();
-  ie->services_supported = importer::HISTORY | importer::FAVORITES |
-      importer::COOKIES | importer::PASSWORDS | importer::SEARCH_ENGINES;
+  importer::SourceProfile ie;
+  ie.importer_name = l10n_util::GetStringUTF16(IDS_IMPORT_FROM_IE);
+  ie.importer_type = importer::TYPE_IE;
+  ie.services_supported = importer::HISTORY | importer::FAVORITES |
+                          importer::COOKIES | importer::PASSWORDS |
+                          importer::SEARCH_ENGINES;
   profiles->push_back(ie);
 }
 
-void DetectEdgeProfiles(std::vector<importer::SourceProfile*>* profiles) {
-  importer::SourceProfile* edge = new importer::SourceProfile;
-  edge->importer_name = l10n_util::GetStringUTF16(IDS_IMPORT_FROM_EDGE);
-  edge->importer_type = importer::TYPE_EDGE;
-  edge->services_supported = importer::FAVORITES;
-  edge->source_path = importer::GetEdgeDataFilePath();
+void DetectEdgeProfiles(std::vector<importer::SourceProfile>* profiles) {
+  importer::SourceProfile edge;
+  edge.importer_name = l10n_util::GetStringUTF16(IDS_IMPORT_FROM_EDGE);
+  edge.importer_type = importer::TYPE_EDGE;
+  edge.services_supported = importer::FAVORITES;
+  edge.source_path = importer::GetEdgeDataFilePath();
   profiles->push_back(edge);
 }
 
 void DetectBuiltinWindowsProfiles(
-    std::vector<importer::SourceProfile*>* profiles) {
+    std::vector<importer::SourceProfile>* profiles) {
   // Make the assumption on Windows 10 that Edge exists and is probably default.
   if (importer::EdgeImporterCanImport())
     DetectEdgeProfiles(profiles);
@@ -62,18 +61,16 @@
 #endif  // defined(OS_WIN)
 
 #if defined(OS_MACOSX)
-void DetectSafariProfiles(std::vector<importer::SourceProfile*>* profiles) {
+void DetectSafariProfiles(std::vector<importer::SourceProfile>* profiles) {
   DCHECK_CURRENTLY_ON(BrowserThread::FILE);
   uint16 items = importer::NONE;
   if (!SafariImporterCanImport(base::mac::GetUserLibraryPath(), &items))
     return;
 
-  importer::SourceProfile* safari = new importer::SourceProfile;
-  safari->importer_name = l10n_util::GetStringUTF16(IDS_IMPORT_FROM_SAFARI);
-  safari->importer_type = importer::TYPE_SAFARI;
-  safari->source_path.clear();
-  safari->app_path.clear();
-  safari->services_supported = items;
+  importer::SourceProfile safari;
+  safari.importer_name = l10n_util::GetStringUTF16(IDS_IMPORT_FROM_SAFARI);
+  safari.importer_type = importer::TYPE_SAFARI;
+  safari.services_supported = items;
   profiles->push_back(safari);
 }
 #endif  // defined(OS_MACOSX)
@@ -82,7 +79,7 @@
 // locale-specific search engines feature (see firefox_importer.cc for
 // details).
 void DetectFirefoxProfiles(const std::string locale,
-                           std::vector<importer::SourceProfile*>* profiles) {
+                           std::vector<importer::SourceProfile>* profiles) {
   DCHECK_CURRENTLY_ON(BrowserThread::FILE);
   base::FilePath profile_path = GetFirefoxProfilePath();
   if (profile_path.empty())
@@ -105,28 +102,28 @@
     return;
   }
 
-  importer::SourceProfile* firefox = new importer::SourceProfile;
-  firefox->importer_name = GetFirefoxImporterName(app_path);
-  firefox->importer_type = firefox_type;
-  firefox->source_path = profile_path;
+  importer::SourceProfile firefox;
+  firefox.importer_name = GetFirefoxImporterName(app_path);
+  firefox.importer_type = firefox_type;
+  firefox.source_path = profile_path;
 #if defined(OS_WIN)
-  firefox->app_path = GetFirefoxInstallPathFromRegistry();
+  firefox.app_path = GetFirefoxInstallPathFromRegistry();
 #endif
-  if (firefox->app_path.empty())
-    firefox->app_path = app_path;
-  firefox->services_supported = importer::HISTORY | importer::FAVORITES |
-                                importer::PASSWORDS | importer::SEARCH_ENGINES |
-                                importer::AUTOFILL_FORM_DATA;
-  firefox->locale = locale;
+  if (firefox.app_path.empty())
+    firefox.app_path = app_path;
+  firefox.services_supported = importer::HISTORY | importer::FAVORITES |
+                               importer::PASSWORDS | importer::SEARCH_ENGINES |
+                               importer::AUTOFILL_FORM_DATA;
+  firefox.locale = locale;
   profiles->push_back(firefox);
 }
 
-std::vector<importer::SourceProfile*> DetectSourceProfilesWorker(
+std::vector<importer::SourceProfile> DetectSourceProfilesWorker(
     const std::string& locale,
     bool include_interactive_profiles) {
   DCHECK_CURRENTLY_ON(BrowserThread::FILE);
 
-  std::vector<importer::SourceProfile*> profiles;
+  std::vector<importer::SourceProfile> profiles;
 
   // The first run import will automatically take settings from the first
   // profile detected, which should be the user's current default.
@@ -150,11 +147,11 @@
   DetectFirefoxProfiles(locale, &profiles);
 #endif
   if (include_interactive_profiles) {
-    importer::SourceProfile* bookmarks_profile = new importer::SourceProfile;
-    bookmarks_profile->importer_name =
+    importer::SourceProfile bookmarks_profile;
+    bookmarks_profile.importer_name =
         l10n_util::GetStringUTF16(IDS_IMPORT_FROM_BOOKMARKS_HTML_FILE);
-    bookmarks_profile->importer_type = importer::TYPE_BOOKMARKS_FILE;
-    bookmarks_profile->services_supported = importer::FAVORITES;
+    bookmarks_profile.importer_type = importer::TYPE_BOOKMARKS_FILE;
+    bookmarks_profile.services_supported = importer::FAVORITES;
     profiles.push_back(bookmarks_profile);
   }
 
@@ -191,12 +188,12 @@
 const importer::SourceProfile& ImporterList::GetSourceProfileAt(
     size_t index) const {
   DCHECK_LT(index, count());
-  return *source_profiles_[index];
+  return source_profiles_[index];
 }
 
 void ImporterList::SourceProfilesLoaded(
     const base::Closure& profiles_loaded_callback,
-    const std::vector<importer::SourceProfile*>& profiles) {
+    const std::vector<importer::SourceProfile>& profiles) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   source_profiles_.assign(profiles.begin(), profiles.end());
diff --git a/chrome/browser/importer/importer_list.h b/chrome/browser/importer/importer_list.h
index 03ba8be3..2a5e4d9c 100644
--- a/chrome/browser/importer/importer_list.h
+++ b/chrome/browser/importer/importer_list.h
@@ -10,13 +10,9 @@
 
 #include "base/basictypes.h"
 #include "base/callback_forward.h"
-#include "base/memory/scoped_vector.h"
 #include "base/memory/weak_ptr.h"
 #include "base/strings/string16.h"
-
-namespace importer {
-struct SourceProfile;
-}
+#include "chrome/common/importer/importer_data_types.h"
 
 // ImporterList detects installed browsers and profiles via
 // DetectSourceProfilesWorker(). ImporterList lives on the UI thread.
@@ -47,14 +43,14 @@
   const importer::SourceProfile& GetSourceProfileAt(size_t index) const;
 
  private:
-  // Called when the source profiles are loaded. Takes ownership of the
-  // loaded profiles in |profiles| and calls |profiles_loaded_callback|.
+  // Called when the source profiles are loaded. Copies the loaded profiles
+  // in |profiles| and calls |profiles_loaded_callback|.
   void SourceProfilesLoaded(
       const base::Closure& profiles_loaded_callback,
-      const std::vector<importer::SourceProfile*>& profiles);
+      const std::vector<importer::SourceProfile>& profiles);
 
   // The list of profiles with the default one first.
-  ScopedVector<importer::SourceProfile> source_profiles_;
+  std::vector<importer::SourceProfile> source_profiles_;
 
   base::WeakPtrFactory<ImporterList> weak_ptr_factory_;
 
diff --git a/chrome/browser/io_thread.cc b/chrome/browser/io_thread.cc
index a5ae645c..cc33dc19 100644
--- a/chrome/browser/io_thread.cc
+++ b/chrome/browser/io_thread.cc
@@ -116,7 +116,7 @@
 #include "net/cert_net/nss_ocsp.h"
 #endif
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
 #include "base/android/build_info.h"
 #include "chrome/browser/android/data_usage/external_data_use_observer.h"
 #include "chrome/browser/android/net/external_estimate_provider_android.h"
@@ -636,7 +636,7 @@
 #endif
 
   scoped_ptr<data_usage::DataUseAmortizer> data_use_amortizer;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
   data_use_amortizer.reset(new data_usage::android::TrafficStatsAmortizer());
 #endif
 
@@ -658,7 +658,7 @@
       globals_->data_use_aggregator.get(),
       true /* is_data_usage_off_the_record */);
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
   globals_->external_data_use_observer.reset(
       new chrome::android::ExternalDataUseObserver(
           globals_->data_use_aggregator.get(),
@@ -679,7 +679,7 @@
                                  &network_quality_estimator_params);
 
   scoped_ptr<net::ExternalEstimateProvider> external_estimate_provider;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
   external_estimate_provider.reset(
       new chrome::android::ExternalEstimateProviderAndroid());
 #endif
diff --git a/chrome/browser/io_thread.h b/chrome/browser/io_thread.h
index 96e10964..e8b4ac3 100644
--- a/chrome/browser/io_thread.h
+++ b/chrome/browser/io_thread.h
@@ -19,6 +19,7 @@
 #include "base/strings/string_piece.h"
 #include "base/time/time.h"
 #include "chrome/browser/net/chrome_network_delegate.h"
+#include "chrome/common/features.h"
 #include "components/ssl_config/ssl_config_service_manager.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/browser_thread_delegate.h"
@@ -35,13 +36,13 @@
 class CommandLine;
 }
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
 namespace chrome {
 namespace android {
 class ExternalDataUseObserver;
 }
 }
-#endif  // defined(OS_ANDROID)
+#endif  // BUILDFLAG(ANDROID_JAVA_UI)
 
 namespace chrome_browser_net {
 class DnsProbeService;
@@ -138,11 +139,11 @@
     // Global aggregator of data use. It must outlive the
     // |system_network_delegate|.
     scoped_ptr<data_usage::DataUseAggregator> data_use_aggregator;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
     // An external observer of data use.
     scoped_ptr<chrome::android::ExternalDataUseObserver>
         external_data_use_observer;
-#endif  // defined(OS_ANDROID)
+#endif  // BUILDFLAG(ANDROID_JAVA_UI)
     // The "system" NetworkDelegate, used for Profile-agnostic network events.
     scoped_ptr<net::NetworkDelegate> system_network_delegate;
     scoped_ptr<net::HostResolver> host_resolver;
diff --git a/chrome/browser/media/media_stream_devices_controller.cc b/chrome/browser/media/media_stream_devices_controller.cc
index c01e52e..44f449b 100644
--- a/chrome/browser/media/media_stream_devices_controller.cc
+++ b/chrome/browser/media/media_stream_devices_controller.cc
@@ -22,6 +22,7 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/common/chrome_switches.h"
+#include "chrome/common/features.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/grit/generated_resources.h"
 #include "components/content_settings/core/browser/host_content_settings_map.h"
@@ -37,14 +38,14 @@
 #include "grit/theme_resources.h"
 #include "ui/base/l10n/l10n_util.h"
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
 #include <vector>
 
 #include "chrome/browser/android/preferences/pref_service_bridge.h"
 #include "chrome/browser/permissions/permission_update_infobar_delegate_android.h"
 #include "content/public/browser/android/content_view_core.h"
 #include "ui/android/window_android.h"
-#endif  // OS_ANDROID
+#endif  // BUILDFLAG(ANDROID_JAVA_UI)
 
 using content::BrowserThread;
 
@@ -170,7 +171,7 @@
     return;
   }
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
   std::vector<ContentSettingsType> content_settings_types;
   if (IsAllowedForAudio())
     content_settings_types.push_back(CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC);
@@ -584,7 +585,7 @@
 
 bool MediaStreamDevicesController::IsUserAcceptAllowed(
     ContentSettingsType content_type) const {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
   content::ContentViewCore* cvc =
       content::ContentViewCore::FromWebContents(web_contents_);
   if (!cvc)
diff --git a/chrome/browser/media/permission_bubble_media_access_handler.cc b/chrome/browser/media/permission_bubble_media_access_handler.cc
index 4c89392..abdec56d 100644
--- a/chrome/browser/media/permission_bubble_media_access_handler.cc
+++ b/chrome/browser/media/permission_bubble_media_access_handler.cc
@@ -9,6 +9,7 @@
 #include "chrome/browser/media/media_stream_device_permissions.h"
 #include "chrome/browser/media/media_stream_devices_controller.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/common/features.h"
 #include "chrome/common/pref_names.h"
 #include "components/content_settings/core/browser/host_content_settings_map.h"
 #include "content/public/browser/browser_thread.h"
@@ -16,7 +17,7 @@
 #include "content/public/browser/notification_types.h"
 #include "content/public/browser/web_contents.h"
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
 #include <vector>
 
 #include "base/bind.h"
@@ -25,9 +26,9 @@
 #include "chrome/browser/permissions/permission_update_infobar_delegate_android.h"
 #else
 #include "chrome/browser/ui/website_settings/permission_bubble_manager.h"
-#endif  // OS_ANDROID
+#endif  // BUILDFLAG(ANDROID_JAVA_UI)
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
 namespace {
 // Callback for the permission update infobar when the site and Chrome
 // permissions are mismatched on Android.
@@ -40,7 +41,7 @@
 }
 }  // namespace
 
-#endif  // OS_ANDROID
+#endif  // BUILDFLAG(ANDROID_JAVA_UI)
 
 using content::BrowserThread;
 
@@ -141,7 +142,7 @@
               &PermissionBubbleMediaAccessHandler::OnAccessRequestResponse,
               base::Unretained(this), web_contents)));
   if (!controller->IsAskingForAudio() && !controller->IsAskingForVideo()) {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
     // If either audio or video was previously allowed and Chrome no longer has
     // the necessary permissions, show a infobar to attempt to address this
     // mismatch.
@@ -165,7 +166,7 @@
     return;
   }
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
   MediaStreamInfoBarDelegateAndroid::Create(web_contents, controller.Pass());
 #else
   PermissionBubbleManager* bubble_manager =
diff --git a/chrome/browser/media/router/media_router.mojom b/chrome/browser/media/router/media_router.mojom
index 6289a2d..060ad71b 100644
--- a/chrome/browser/media/router/media_router.mojom
+++ b/chrome/browser/media/router/media_router.mojom
@@ -18,6 +18,8 @@
   string sink_id;
   // The human-readable name, e.g. "Janet's Chromecast".
   string name;
+  // Optional description of the sink.
+  string? description;
   // The type of icon to show in the UI for this media sink.
   IconType icon_type;
 };
diff --git a/chrome/browser/media/router/media_router_dialog_controller.cc b/chrome/browser/media/router/media_router_dialog_controller.cc
index 0d8506a..757bc9d 100644
--- a/chrome/browser/media/router/media_router_dialog_controller.cc
+++ b/chrome/browser/media/router/media_router_dialog_controller.cc
@@ -5,11 +5,12 @@
 #include "chrome/browser/media/router/media_router_dialog_controller.h"
 
 #include "chrome/browser/media/router/media_router_metrics.h"
+#include "chrome/common/features.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_delegate.h"
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
 #include "chrome/browser/media/android/router/media_router_dialog_controller_android.h"
 #else
 #include "chrome/browser/ui/webui/media_router/media_router_dialog_controller_impl.h"
@@ -21,7 +22,7 @@
 MediaRouterDialogController*
 MediaRouterDialogController::GetOrCreateForWebContents(
     content::WebContents* contents) {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
   return MediaRouterDialogControllerAndroid::GetOrCreateForWebContents(
       contents);
 #else
diff --git a/chrome/browser/media/router/media_router_type_converters.cc b/chrome/browser/media/router/media_router_type_converters.cc
index 627bf9de..6541dbfb 100644
--- a/chrome/browser/media/router/media_router_type_converters.cc
+++ b/chrome/browser/media/router/media_router_type_converters.cc
@@ -59,8 +59,12 @@
 media_router::MediaSink
 TypeConverter<media_router::MediaSink, MediaSinkPtr>::Convert(
     const MediaSinkPtr& input) {
-  return media_router::MediaSink(input->sink_id, input->name,
-                                 SinkIconTypeFromMojo(input->icon_type));
+  media_router::MediaSink sink(input->sink_id, input->name,
+                               SinkIconTypeFromMojo(input->icon_type));
+  if (!input->description.get().empty())
+    sink.set_description(input->description);
+
+  return sink;
 }
 
 // static
diff --git a/chrome/browser/media/router/media_router_type_converters_unittest.cc b/chrome/browser/media/router/media_router_type_converters_unittest.cc
index 0f6d20e..6838d006 100644
--- a/chrome/browser/media/router/media_router_type_converters_unittest.cc
+++ b/chrome/browser/media/router/media_router_type_converters_unittest.cc
@@ -12,9 +12,12 @@
 
 TEST(MediaRouterTypeConvertersTest, ConvertMediaSink) {
   MediaSink expected_media_sink("sinkId1", "Sink 1", MediaSink::IconType::CAST);
+  expected_media_sink.set_description("description");
+
   interfaces::MediaSinkPtr mojo_sink(interfaces::MediaSink::New());
   mojo_sink->sink_id = "sinkId1";
   mojo_sink->name = "Sink 1";
+  mojo_sink->description = "description";
   mojo_sink->icon_type =
       media_router::interfaces::MediaSink::IconType::ICON_TYPE_CAST;
 
@@ -25,7 +28,8 @@
   // Convert MediaSink and back should result in identical object.
   EXPECT_EQ(expected_media_sink.name(), media_sink.name());
   EXPECT_EQ(expected_media_sink.id(), media_sink.id());
-  EXPECT_EQ(expected_media_sink.icon_type(), media_sink.icon_type());
+  EXPECT_FALSE(media_sink.description().empty());
+  EXPECT_EQ(expected_media_sink.description(), media_sink.description());
   EXPECT_EQ(expected_media_sink.icon_type(), media_sink.icon_type());
   EXPECT_TRUE(expected_media_sink.Equals(media_sink));
 }
diff --git a/chrome/browser/media/router/media_sink.cc b/chrome/browser/media/router/media_sink.cc
index 66768c3..0b59c5f 100644
--- a/chrome/browser/media/router/media_sink.cc
+++ b/chrome/browser/media/router/media_sink.cc
@@ -18,8 +18,4 @@
   return sink_id_ == other.sink_id_;
 }
 
-bool MediaSink::Empty() const {
-  return sink_id_.empty();
-}
-
 }  // namespace media_router
diff --git a/chrome/browser/media/router/media_sink.h b/chrome/browser/media/router/media_sink.h
index 23df7b19..44d2ed58 100644
--- a/chrome/browser/media/router/media_sink.h
+++ b/chrome/browser/media/router/media_sink.h
@@ -30,19 +30,26 @@
 
   const MediaSink::Id& id() const { return sink_id_; }
   const std::string& name() const { return name_; }
-  MediaSink::IconType icon_type() const { return icon_type_; }
+  void set_description(const std::string& description) {
+    description_ = description;
+  }
+  const std::string& description() const { return description_; }
+  IconType icon_type() const { return icon_type_; }
 
   bool Equals(const MediaSink& other) const;
-  bool Empty() const;
 
  private:
   // Unique identifier for the MediaSink.
   MediaSink::Id sink_id_;
+
   // Descriptive name of the MediaSink.
-  // Optional, can use an empty string if no sink name is available.
   std::string name_;
+
+  // Optional description of the MediaSink.
+  std::string description_;
+
   // The type of icon that corresponds with the MediaSink.
-  MediaSink::IconType icon_type_;
+  IconType icon_type_;
 };
 
 }  // namespace media_router
diff --git a/chrome/browser/media_galleries/linux/mtp_device_delegate_impl_linux.cc b/chrome/browser/media_galleries/linux/mtp_device_delegate_impl_linux.cc
index aacc58a..d00847a 100644
--- a/chrome/browser/media_galleries/linux/mtp_device_delegate_impl_linux.cc
+++ b/chrome/browser/media_galleries/linux/mtp_device_delegate_impl_linux.cc
@@ -6,7 +6,9 @@
 
 #include <errno.h>
 #include <fcntl.h>
+
 #include <algorithm>
+#include <limits>
 #include <vector>
 
 #include "base/bind.h"
@@ -102,7 +104,7 @@
 void CreateDirectoryOnUIThread(
     const std::string& storage_name,
     const bool read_only,
-    const uint32 parent_id,
+    const uint32_t parent_id,
     const std::string& directory_name,
     const MTPDeviceTaskHelper::CreateDirectorySuccessCallback& success_callback,
     const MTPDeviceTaskHelper::ErrorCallback& error_callback) {
@@ -130,7 +132,7 @@
 void ReadDirectoryOnUIThread(
     const std::string& storage_name,
     const bool read_only,
-    const uint32 directory_id,
+    const uint32_t directory_id,
     const size_t max_size,
     const MTPDeviceTaskHelper::ReadDirectorySuccessCallback& success_callback,
     const MTPDeviceTaskHelper::ErrorCallback& error_callback) {
@@ -156,7 +158,7 @@
 void GetFileInfoOnUIThread(
     const std::string& storage_name,
     const bool read_only,
-    uint32 file_id,
+    uint32_t file_id,
     const MTPDeviceTaskHelper::GetFileInfoSuccessCallback& success_callback,
     const MTPDeviceTaskHelper::ErrorCallback& error_callback) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
@@ -226,7 +228,7 @@
 void RenameObjectOnUIThread(
     const std::string& storage_name,
     const bool read_only,
-    const uint32 object_id,
+    const uint32_t object_id,
     const std::string& new_name,
     const MTPDeviceTaskHelper::RenameObjectSuccessCallback& success_callback,
     const MTPDeviceTaskHelper::ErrorCallback& error_callback) {
@@ -254,7 +256,7 @@
     const std::string& storage_name,
     const bool read_only,
     const int source_file_descriptor,
-    const uint32 parent_id,
+    const uint32_t parent_id,
     const std::string& file_name,
     const MTPDeviceTaskHelper::CopyFileFromLocalSuccessCallback&
         success_callback,
@@ -283,7 +285,7 @@
 void DeleteObjectOnUIThread(
     const std::string storage_name,
     const bool read_only,
-    const uint32 object_id,
+    const uint32_t object_id,
     const MTPDeviceTaskHelper::DeleteObjectSuccessCallback success_callback,
     const MTPDeviceTaskHelper::ErrorCallback error_callback) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
@@ -348,8 +350,7 @@
 }
 
 // A fake callback to be passed as CopyFileProgressCallback.
-void FakeCopyFileProgressCallback(int64 size) {
-}
+void FakeCopyFileProgressCallback(int64_t size) {}
 
 }  // namespace
 
@@ -371,7 +372,7 @@
 // Lives on the IO thread.
 class MTPDeviceDelegateImplLinux::MTPFileNode {
  public:
-  MTPFileNode(uint32 file_id,
+  MTPFileNode(uint32_t file_id,
               const std::string& file_name,
               MTPFileNode* parent,
               FileIdToMTPFileNodeMap* file_id_to_node_map);
@@ -379,17 +380,17 @@
 
   const MTPFileNode* GetChild(const std::string& name) const;
 
-  void EnsureChildExists(const std::string& name, uint32 id);
+  void EnsureChildExists(const std::string& name, uint32_t id);
 
   // Clears all the children, except those in |children_to_keep|.
   void ClearNonexistentChildren(
       const std::set<std::string>& children_to_keep);
 
-  bool DeleteChild(uint32 file_id);
+  bool DeleteChild(uint32_t file_id);
 
   bool HasChildren() const;
 
-  uint32 file_id() const { return file_id_; }
+  uint32_t file_id() const { return file_id_; }
   const std::string& file_name() const { return file_name_; }
   MTPFileNode* parent() { return parent_; }
 
@@ -398,7 +399,7 @@
   typedef base::ScopedPtrHashMap<std::string, scoped_ptr<MTPFileNode>>
       ChildNodes;
 
-  const uint32 file_id_;
+  const uint32_t file_id_;
   const std::string file_name_;
 
   ChildNodes children_;
@@ -409,7 +410,7 @@
 };
 
 MTPDeviceDelegateImplLinux::MTPFileNode::MTPFileNode(
-    uint32 file_id,
+    uint32_t file_id,
     const std::string& file_name,
     MTPFileNode* parent,
     FileIdToMTPFileNodeMap* file_id_to_node_map)
@@ -438,7 +439,7 @@
 
 void MTPDeviceDelegateImplLinux::MTPFileNode::EnsureChildExists(
     const std::string& name,
-    uint32 id) {
+    uint32_t id) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
   const MTPFileNode* child = GetChild(name);
   if (child && child->file_id() == id)
@@ -465,7 +466,7 @@
   }
 }
 
-bool MTPDeviceDelegateImplLinux::MTPFileNode::DeleteChild(uint32 file_id) {
+bool MTPDeviceDelegateImplLinux::MTPFileNode::DeleteChild(uint32_t file_id) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
   for (ChildNodes::iterator it = children_.begin();
        it != children_.end(); ++it) {
@@ -615,7 +616,7 @@
 void MTPDeviceDelegateImplLinux::ReadBytes(
     const base::FilePath& device_file_path,
     const scoped_refptr<net::IOBuffer>& buf,
-    int64 offset,
+    int64_t offset,
     int buf_len,
     const ReadBytesSuccessCallback& success_callback,
     const ErrorCallback& error_callback) {
@@ -835,7 +836,7 @@
     const ErrorCallback& error_callback) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
 
-  uint32 file_id;
+  uint32_t file_id;
   if (CachedPathToId(file_path, &file_id)) {
     GetFileInfoSuccessCallback success_callback_wrapper =
         base::Bind(&MTPDeviceDelegateImplLinux::OnDidGetFileInfo,
@@ -878,7 +879,7 @@
   if (other_components.empty()) {
     // Either we reached the last component in the recursive case, or this is
     // the non-recursive case.
-    uint32 parent_id;
+    uint32_t parent_id;
     if (CachedPathToId(current_component.DirName(), &parent_id)) {
       const base::Closure closure =
           base::Bind(&MTPDeviceDelegateImplLinux::CreateSingleDirectory,
@@ -891,7 +892,7 @@
     }
   } else {
     // Ensures that parent directories are created for recursive case.
-    uint32 directory_id;
+    uint32_t directory_id;
     if (CachedPathToId(current_component, &directory_id)) {
       // Parent directory |current_component| already exists, continue creating
       // directories.
@@ -934,7 +935,7 @@
     const ErrorCallback& error_callback) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
 
-  uint32 dir_id;
+  uint32_t dir_id;
   if (CachedPathToId(root, &dir_id)) {
     GetFileInfoSuccessCallback success_callback_wrapper =
         base::Bind(&MTPDeviceDelegateImplLinux::OnDidGetFileInfoToReadDirectory,
@@ -970,7 +971,7 @@
     const ErrorCallback& error_callback) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
 
-  uint32 file_id;
+  uint32_t file_id;
   if (CachedPathToId(device_file_path, &file_id)) {
     scoped_ptr<SnapshotRequestInfo> request_info(
         new SnapshotRequestInfo(file_id,
@@ -1005,12 +1006,14 @@
 
 void MTPDeviceDelegateImplLinux::ReadBytesInternal(
     const base::FilePath& device_file_path,
-    net::IOBuffer* buf, int64 offset, int buf_len,
+    net::IOBuffer* buf,
+    int64_t offset,
+    int buf_len,
     const ReadBytesSuccessCallback& success_callback,
     const ErrorCallback& error_callback) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
 
-  uint32 file_id;
+  uint32_t file_id;
   if (CachedPathToId(device_file_path, &file_id)) {
     ReadBytesRequest request(
         file_id, buf, offset, buf_len,
@@ -1050,7 +1053,7 @@
 
   if (source_file_path.DirName() == device_file_path.DirName()) {
     // If a file is moved in a same directory, rename the file.
-    uint32 file_id;
+    uint32_t file_id;
     if (CachedPathToId(source_file_path, &file_id)) {
       const MTPDeviceTaskHelper::RenameObjectSuccessCallback
           success_callback_wrapper = base::Bind(
@@ -1097,7 +1100,7 @@
   }
 
   const int source_file_descriptor = open_fd_result.first;
-  uint32 parent_id;
+  uint32_t parent_id;
   if (CachedPathToId(device_file_path.DirName(), &parent_id)) {
     CopyFileFromLocalSuccessCallback success_callback_wrapper =
         base::Bind(&MTPDeviceDelegateImplLinux::OnDidCopyFileFromLocal,
@@ -1135,7 +1138,7 @@
   if (file_info.is_directory) {
     error_callback.Run(base::File::FILE_ERROR_NOT_A_FILE);
   } else {
-    uint32 file_id;
+    uint32_t file_id;
     if (CachedPathToId(file_path, &file_id))
       RunDeleteObjectOnUIThread(file_path, file_id, success_callback,
                                 error_callback);
@@ -1156,7 +1159,7 @@
     return;
   }
 
-  uint32 directory_id;
+  uint32_t directory_id;
   if (!CachedPathToId(file_path, &directory_id)) {
     error_callback.Run(base::File::FILE_ERROR_NOT_FOUND);
     return;
@@ -1234,7 +1237,7 @@
 
 void MTPDeviceDelegateImplLinux::OnDidReadDirectoryToDeleteDirectory(
     const base::FilePath& directory_path,
-    const uint32 directory_id,
+    const uint32_t directory_id,
     const DeleteDirectorySuccessCallback& success_callback,
     const ErrorCallback& error_callback,
     const MTPDeviceTaskHelper::MTPEntries& entries,
@@ -1254,7 +1257,7 @@
 
 void MTPDeviceDelegateImplLinux::RunDeleteObjectOnUIThread(
     const base::FilePath& object_path,
-    const uint32 object_id,
+    const uint32_t object_id,
     const DeleteObjectSuccessCallback& success_callback,
     const ErrorCallback& error_callback) {
   const MTPDeviceTaskHelper::DeleteObjectSuccessCallback
@@ -1406,7 +1409,7 @@
     return;
   }
 
-  uint32 parent_id;
+  uint32_t parent_id;
   if (!CachedPathToId(directory_path.DirName(), &parent_id)) {
     error_callback.Run(base::File::FILE_ERROR_NOT_FOUND);
     return;
@@ -1428,7 +1431,7 @@
 }
 
 void MTPDeviceDelegateImplLinux::OnDidGetFileInfoToReadDirectory(
-    uint32 dir_id,
+    uint32_t dir_id,
     const ReadDirectorySuccessCallback& success_callback,
     const ErrorCallback& error_callback,
     const base::File::Info& file_info) {
@@ -1462,7 +1465,8 @@
   base::File::Error error = base::File::FILE_OK;
   if (file_info.is_directory)
     error = base::File::FILE_ERROR_NOT_A_FILE;
-  else if (file_info.size < 0 || file_info.size > kuint32max)
+  else if (file_info.size < 0 ||
+           file_info.size > std::numeric_limits<uint32_t>::max())
     error = base::File::FILE_ERROR_FAILED;
 
   if (error != base::File::FILE_OK)
@@ -1560,7 +1564,7 @@
 }
 
 void MTPDeviceDelegateImplLinux::OnDidReadDirectory(
-    uint32 dir_id,
+    uint32_t dir_id,
     const ReadDirectorySuccessCallback& success_callback,
     const MTPDeviceTaskHelper::MTPEntries& mtp_entries,
     bool has_more) {
@@ -1717,7 +1721,7 @@
 void MTPDeviceDelegateImplLinux::OnDidMoveFileLocalWithRename(
     const MoveFileLocalSuccessCallback& success_callback,
     const base::FilePath& source_file_path,
-    const uint32 file_id) {
+    const uint32_t file_id) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
 
   EvictCachedPathToId(file_id);
@@ -1775,7 +1779,7 @@
 
 void MTPDeviceDelegateImplLinux::OnDidDeleteObject(
     const base::FilePath& object_path,
-    const uint32 object_id,
+    const uint32_t object_id,
     const DeleteObjectSuccessCallback success_callback) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
 
@@ -1798,7 +1802,7 @@
 
 void MTPDeviceDelegateImplLinux::HandleDeviceFileError(
     const ErrorCallback& error_callback,
-    uint32 file_id,
+    uint32_t file_id,
     base::File::Error error) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
 
@@ -1855,9 +1859,8 @@
   ReadDirectoryInternal(uncached_path, success_callback, error_callback);
 }
 
-
 bool MTPDeviceDelegateImplLinux::CachedPathToId(const base::FilePath& path,
-                                                uint32* id) const {
+                                                uint32_t* id) const {
   DCHECK(id);
 
   std::string device_relpath = GetDeviceRelativePath(device_path_, path);
@@ -1878,7 +1881,7 @@
   return true;
 }
 
-void MTPDeviceDelegateImplLinux::EvictCachedPathToId(const uint32 id) {
+void MTPDeviceDelegateImplLinux::EvictCachedPathToId(const uint32_t id) {
   FileIdToMTPFileNodeMap::iterator it = file_id_to_node_map_.find(id);
   if (it != file_id_to_node_map_.end()) {
     DCHECK(!it->second->HasChildren());
diff --git a/chrome/browser/media_galleries/linux/mtp_device_delegate_impl_linux.h b/chrome/browser/media_galleries/linux/mtp_device_delegate_impl_linux.h
index 5b5cee18..97371501 100644
--- a/chrome/browser/media_galleries/linux/mtp_device_delegate_impl_linux.h
+++ b/chrome/browser/media_galleries/linux/mtp_device_delegate_impl_linux.h
@@ -5,6 +5,8 @@
 #ifndef CHROME_BROWSER_MEDIA_GALLERIES_LINUX_MTP_DEVICE_DELEGATE_IMPL_LINUX_H_
 #define CHROME_BROWSER_MEDIA_GALLERIES_LINUX_MTP_DEVICE_DELEGATE_IMPL_LINUX_H_
 
+#include <stdint.h>
+
 #include <deque>
 #include <map>
 #include <set>
@@ -60,7 +62,7 @@
   class MTPFileNode;
 
   // Maps file ids to file nodes.
-  typedef std::map<uint32, MTPFileNode*> FileIdToMTPFileNodeMap;
+  typedef std::map<uint32_t, MTPFileNode*> FileIdToMTPFileNodeMap;
 
   // Maps file paths to file info.
   typedef std::map<base::FilePath, MTPDeviceTaskHelper::MTPEntry> FileInfoCache;
@@ -96,7 +98,7 @@
   bool IsStreaming() override;
   void ReadBytes(const base::FilePath& device_file_path,
                  const scoped_refptr<net::IOBuffer>& buf,
-                 int64 offset,
+                 int64_t offset,
                  int buf_len,
                  const ReadBytesSuccessCallback& success_callback,
                  const ErrorCallback& error_callback) override;
@@ -160,7 +162,9 @@
       const ErrorCallback& error_callback);
   virtual void ReadBytesInternal(
       const base::FilePath& device_file_path,
-      net::IOBuffer* buf, int64 offset, int buf_len,
+      net::IOBuffer* buf,
+      int64_t offset,
+      int buf_len,
       const ReadBytesSuccessCallback& success_callback,
       const ErrorCallback& error_callback);
   virtual void MoveFileLocalInternal(
@@ -207,7 +211,7 @@
   // Called when ReadDirectory succeeds.
   virtual void OnDidReadDirectoryToDeleteDirectory(
       const base::FilePath& directory_path,
-      const uint32 directory_id,
+      const uint32_t directory_id,
       const DeleteDirectorySuccessCallback& success_callback,
       const ErrorCallback& error_callback,
       const MTPDeviceTaskHelper::MTPEntries& entries,
@@ -216,7 +220,7 @@
   // Calls DeleteObjectOnUIThread on UI thread.
   virtual void RunDeleteObjectOnUIThread(
       const base::FilePath& object_path,
-      const uint32 object_id,
+      const uint32_t object_id,
       const DeleteObjectSuccessCallback& success_callback,
       const ErrorCallback& error_callback);
 
@@ -289,7 +293,7 @@
   // If |dir_id| is not a directory, |error_callback| is invoked to notify the
   // caller about the file error and process the next pending request.
   void OnDidGetFileInfoToReadDirectory(
-      uint32 dir_id,
+      uint32_t dir_id,
       const ReadDirectorySuccessCallback& success_callback,
       const ErrorCallback& error_callback,
       const base::File::Info& file_info);
@@ -347,7 +351,7 @@
   // file entries.
   // |file_list| contains the directory file entries with their file ids.
   // |has_more| is true if there are more file entries to read.
-  void OnDidReadDirectory(uint32 dir_id,
+  void OnDidReadDirectory(uint32_t dir_id,
                           const ReadDirectorySuccessCallback& success_callback,
                           const MTPDeviceTaskHelper::MTPEntries& mtp_entries,
                           bool has_more);
@@ -413,7 +417,7 @@
   void OnDidMoveFileLocalWithRename(
       const MoveFileLocalSuccessCallback& success_callback,
       const base::FilePath& source_file_path,
-      const uint32 file_id);
+      const uint32_t file_id);
 
   // Called when CopyFileFromLocal() succeeds.
   void OnDidCopyFileFromLocal(
@@ -433,7 +437,7 @@
 
   // Called when DeleteObject() succeeds.
   void OnDidDeleteObject(const base::FilePath& object_path,
-                         const uint32 object_id,
+                         const uint32_t object_id,
                          const DeleteObjectSuccessCallback success_callback);
 
   // Called when DeleteFileOrDirectory() fails.
@@ -443,7 +447,7 @@
   // Handles the device file |error| while operating on |file_id|.
   // |error_callback| is invoked to notify the caller about the file error.
   void HandleDeviceFileError(const ErrorCallback& error_callback,
-                             uint32 file_id,
+                             uint32_t file_id,
                              base::File::Error error);
 
   // Given a full path, returns a non-empty sub-path that needs to be read into
@@ -458,10 +462,10 @@
 
   // Given a full path, if it exists in the cache, writes the file's id to |id|
   // and return true.
-  bool CachedPathToId(const base::FilePath& path, uint32* id) const;
+  bool CachedPathToId(const base::FilePath& path, uint32_t* id) const;
 
   // Evict the cache of |id|.
-  void EvictCachedPathToId(const uint32 id);
+  void EvictCachedPathToId(const uint32_t id);
 
   // MTP device initialization state.
   InitializationState init_state_;
diff --git a/chrome/browser/media_galleries/linux/mtp_device_task_helper.cc b/chrome/browser/media_galleries/linux/mtp_device_task_helper.cc
index c7596ea..48a790f 100644
--- a/chrome/browser/media_galleries/linux/mtp_device_task_helper.cc
+++ b/chrome/browser/media_galleries/linux/mtp_device_task_helper.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/media_galleries/linux/mtp_device_task_helper.h"
 
 #include <algorithm>
+#include <limits>
 
 #include "base/logging.h"
 #include "chrome/browser/media_galleries/linux/mtp_device_object_enumerator.h"
@@ -76,7 +77,7 @@
 }
 
 void MTPDeviceTaskHelper::GetFileInfo(
-    uint32 file_id,
+    uint32_t file_id,
     const GetFileInfoSuccessCallback& success_callback,
     const ErrorCallback& error_callback) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
@@ -92,7 +93,7 @@
 }
 
 void MTPDeviceTaskHelper::CreateDirectory(
-    const uint32 parent_id,
+    const uint32_t parent_id,
     const std::string& directory_name,
     const CreateDirectorySuccessCallback& success_callback,
     const ErrorCallback& error_callback) {
@@ -108,7 +109,7 @@
 }
 
 void MTPDeviceTaskHelper::ReadDirectory(
-    const uint32 directory_id,
+    const uint32_t directory_id,
     const size_t max_size,
     const ReadDirectorySuccessCallback& success_callback,
     const ErrorCallback& error_callback) {
@@ -153,7 +154,7 @@
 }
 
 void MTPDeviceTaskHelper::RenameObject(
-    const uint32 object_id,
+    const uint32_t object_id,
     const std::string& new_name,
     const RenameObjectSuccessCallback& success_callback,
     const ErrorCallback& error_callback) {
@@ -172,7 +173,7 @@
 void MTPDeviceTaskHelper::CopyFileFromLocal(
     const std::string& storage_name,
     const int source_file_descriptor,
-    const uint32 parent_id,
+    const uint32_t parent_id,
     const std::string& file_name,
     const CopyFileFromLocalSuccessCallback& success_callback,
     const ErrorCallback& error_callback) {
@@ -186,7 +187,7 @@
 }
 
 void MTPDeviceTaskHelper::DeleteObject(
-    const uint32 object_id,
+    const uint32_t object_id,
     const DeleteObjectSuccessCallback& success_callback,
     const ErrorCallback& error_callback) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
@@ -296,7 +297,8 @@
   if (file_info.is_directory) {
     return HandleDeviceError(request.error_callback,
                              base::File::FILE_ERROR_NOT_A_FILE);
-  } else if (file_info.size < 0 || file_info.size > kuint32max ||
+  } else if (file_info.size < 0 ||
+             file_info.size > std::numeric_limits<uint32_t>::max() ||
              request.offset > file_info.size) {
     return HandleDeviceError(request.error_callback,
                              base::File::FILE_ERROR_FAILED);
@@ -308,15 +310,13 @@
     return;
   }
 
-  uint32 bytes_to_read = std::min(
-      base::checked_cast<uint32>(request.buf_len),
-      base::saturated_cast<uint32>(file_info.size - request.offset));
+  uint32_t bytes_to_read =
+      std::min(base::checked_cast<uint32_t>(request.buf_len),
+               base::saturated_cast<uint32_t>(file_info.size - request.offset));
 
   GetMediaTransferProtocolManager()->ReadFileChunk(
-      device_handle_,
-      request.file_id,
-      base::checked_cast<uint32>(request.offset),
-      bytes_to_read,
+      device_handle_, request.file_id,
+      base::checked_cast<uint32_t>(request.offset), bytes_to_read,
       base::Bind(&MTPDeviceTaskHelper::OnDidReadBytes,
                  weak_ptr_factory_.GetWeakPtr(), request, file_info));
 }
diff --git a/chrome/browser/media_galleries/linux/mtp_device_task_helper.h b/chrome/browser/media_galleries/linux/mtp_device_task_helper.h
index 5af1487..2a73e17 100644
--- a/chrome/browser/media_galleries/linux/mtp_device_task_helper.h
+++ b/chrome/browser/media_galleries/linux/mtp_device_task_helper.h
@@ -5,6 +5,8 @@
 #ifndef CHROME_BROWSER_MEDIA_GALLERIES_LINUX_MTP_DEVICE_TASK_HELPER_H_
 #define CHROME_BROWSER_MEDIA_GALLERIES_LINUX_MTP_DEVICE_TASK_HELPER_H_
 
+#include <stdint.h>
+
 #include <string>
 #include <vector>
 
diff --git a/chrome/browser/media_galleries/linux/snapshot_file_details.cc b/chrome/browser/media_galleries/linux/snapshot_file_details.cc
index e2408bad..1058fd5 100644
--- a/chrome/browser/media_galleries/linux/snapshot_file_details.cc
+++ b/chrome/browser/media_galleries/linux/snapshot_file_details.cc
@@ -4,6 +4,8 @@
 
 #include "chrome/browser/media_galleries/linux/snapshot_file_details.h"
 
+#include <limits>
+
 #include "base/numerics/safe_conversions.h"
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -11,7 +13,7 @@
 ////////////////////////////////////////////////////////////////////////////////
 
 SnapshotRequestInfo::SnapshotRequestInfo(
-    uint32 file_id,
+    uint32_t file_id,
     const base::FilePath& snapshot_file_path,
     const MTPDeviceAsyncDelegate::CreateSnapshotFileSuccessCallback&
         success_callback,
@@ -19,8 +21,7 @@
     : file_id(file_id),
       snapshot_file_path(snapshot_file_path),
       success_callback(success_callback),
-      error_callback(error_callback) {
-}
+      error_callback(error_callback) {}
 
 SnapshotRequestInfo::~SnapshotRequestInfo() {
 }
@@ -45,9 +46,9 @@
   error_occurred_ = error;
 }
 
-bool SnapshotFileDetails::AddBytesWritten(uint32 bytes_written) {
+bool SnapshotFileDetails::AddBytesWritten(uint32_t bytes_written) {
   if ((bytes_written == 0) ||
-      (bytes_written_ > kuint32max - bytes_written) ||
+      (bytes_written_ > std::numeric_limits<uint32_t>::max() - bytes_written) ||
       (bytes_written_ + bytes_written > file_info_.size))
     return false;
 
@@ -59,10 +60,10 @@
   return !error_occurred_ && (bytes_written_ == file_info_.size);
 }
 
-uint32 SnapshotFileDetails::BytesToRead() const {
+uint32_t SnapshotFileDetails::BytesToRead() const {
   // Read data in 1MB chunks.
-  static const uint32 kReadChunkSize = 1024 * 1024;
+  static const uint32_t kReadChunkSize = 1024 * 1024;
   return std::min(
       kReadChunkSize,
-      base::checked_cast<uint32>(file_info_.size) - bytes_written_);
+      base::checked_cast<uint32_t>(file_info_.size) - bytes_written_);
 }
diff --git a/chrome/browser/media_galleries/linux/snapshot_file_details.h b/chrome/browser/media_galleries/linux/snapshot_file_details.h
index 0457210..e0e3c39 100644
--- a/chrome/browser/media_galleries/linux/snapshot_file_details.h
+++ b/chrome/browser/media_galleries/linux/snapshot_file_details.h
@@ -5,9 +5,10 @@
 #ifndef CHROME_BROWSER_MEDIA_GALLERIES_LINUX_SNAPSHOT_FILE_DETAILS_H_
 #define CHROME_BROWSER_MEDIA_GALLERIES_LINUX_SNAPSHOT_FILE_DETAILS_H_
 
+#include <stdint.h>
+
 #include <string>
 
-#include "base/basictypes.h"
 #include "base/callback.h"
 #include "base/files/file.h"
 #include "base/files/file_path.h"
@@ -16,7 +17,7 @@
 // Used to represent snapshot file request params.
 struct SnapshotRequestInfo {
   SnapshotRequestInfo(
-      uint32 file_id,
+      uint32_t file_id,
       const base::FilePath& snapshot_file_path,
       const MTPDeviceAsyncDelegate::CreateSnapshotFileSuccessCallback&
           success_callback,
@@ -24,7 +25,7 @@
   ~SnapshotRequestInfo();
 
   // MTP device file id.
-  const uint32 file_id;
+  const uint32_t file_id;
 
   // Local platform path of the snapshot file.
   const base::FilePath snapshot_file_path;
@@ -47,17 +48,13 @@
 
   ~SnapshotFileDetails();
 
-  uint32 file_id() const {
-    return request_info_.file_id;
-  }
+  uint32_t file_id() const { return request_info_.file_id; }
 
   base::FilePath snapshot_file_path() const {
     return request_info_.snapshot_file_path;
   }
 
-  uint32 bytes_written() const {
-    return bytes_written_;
-  }
+  uint32_t bytes_written() const { return bytes_written_; }
 
   const base::File::Info& file_info() const {
     return file_info_;
@@ -85,13 +82,13 @@
   // |bytes_written_|.
   // If |bytes_written| is invalid, returns false and does not add
   // |bytes_written| to |bytes_written_|.
-  bool AddBytesWritten(uint32 bytes_written);
+  bool AddBytesWritten(uint32_t bytes_written);
 
   // Returns true if the snapshot file is created successfully (no more write
   // operation is required to complete the snapshot file).
   bool IsSnapshotFileWriteComplete() const;
 
-  uint32 BytesToRead() const;
+  uint32_t BytesToRead() const;
 
  private:
   // Snapshot file request params.
@@ -101,7 +98,7 @@
   const base::File::Info file_info_;
 
   // Number of bytes written into the snapshot file.
-  uint32 bytes_written_;
+  uint32_t bytes_written_;
 
   // Whether an error occurred during file transfer.
   bool error_occurred_;
diff --git a/chrome/browser/metrics/chrome_metrics_service_accessor.cc b/chrome/browser/metrics/chrome_metrics_service_accessor.cc
index e4416f7c..0fe57ab5 100644
--- a/chrome/browser/metrics/chrome_metrics_service_accessor.cc
+++ b/chrome/browser/metrics/chrome_metrics_service_accessor.cc
@@ -6,6 +6,7 @@
 
 #include "base/prefs/pref_service.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/common/features.h"
 #include "chrome/common/pref_names.h"
 #include "content/public/browser/browser_thread.h"
 
@@ -29,7 +30,7 @@
     return false;
   }
 
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(ANDROID_JAVA_UI)
   return IsMetricsReportingEnabled(g_browser_process->local_state());
 #else
   // Android currently obtain the value for whether the user has
@@ -42,7 +43,7 @@
   pref_value = g_browser_process->local_state()->GetBoolean(
       prefs::kCrashReportingEnabled);
   return IsMetricsReportingEnabledWithPrefValue(pref_value);
-#endif  // !defined(OS_ANDROID)
+#endif  // !BUILDFLAG(ANDROID_JAVA_UI)
 }
 
 // static
diff --git a/chrome/browser/metrics/chrome_metrics_service_client.cc b/chrome/browser/metrics/chrome_metrics_service_client.cc
index 5ffa6f6c..1fbe66d 100644
--- a/chrome/browser/metrics/chrome_metrics_service_client.cc
+++ b/chrome/browser/metrics/chrome_metrics_service_client.cc
@@ -28,6 +28,7 @@
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/crash_keys.h"
+#include "chrome/common/features.h"
 #include "components/metrics/call_stack_profile_metrics_provider.h"
 #include "components/metrics/drive_metrics_provider.h"
 #include "components/metrics/gpu/gpu_metrics_provider.h"
@@ -48,7 +49,7 @@
 #include "content/public/browser/histogram_fetcher.h"
 #include "content/public/browser/notification_service.h"
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
 #include "chrome/browser/metrics/android_metrics_provider.h"
 #endif
 
@@ -113,7 +114,7 @@
 // This should happen only once as the used preference will be initialized
 // afterwards in |UmaSessionStats.java|.
 bool ShouldClearSavedMetrics() {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
   PrefService* local_state = g_browser_process->local_state();
   return !local_state->HasPrefPath(metrics::prefs::kMetricsReportingEnabled) &&
          variations::GetVariationParamValue("UMA_EnableCellularLogUpload",
@@ -170,9 +171,9 @@
   metrics::MetricsService::RegisterPrefs(registry);
   metrics::StabilityMetricsHelper::RegisterPrefs(registry);
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
   AndroidMetricsProvider::RegisterPrefs(registry);
-#endif  // defined(OS_ANDROID)
+#endif  // BUILDFLAG(ANDROID_JAVA_UI)
 
 #if defined(ENABLE_PLUGINS)
   PluginMetricsProvider::RegisterPrefs(registry);
@@ -343,11 +344,11 @@
       scoped_ptr<metrics::MetricsProvider>(
           new metrics::CallStackProfileMetricsProvider));
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
   metrics_service_->RegisterMetricsProvider(
       scoped_ptr<metrics::MetricsProvider>(
           new AndroidMetricsProvider(g_browser_process->local_state())));
-#endif  // defined(OS_ANDROID)
+#endif  // BUILDFLAG(ANDROID_JAVA_UI)
 
 #if defined(OS_WIN)
   google_update_metrics_provider_ = new GoogleUpdateMetricsProviderWin;
diff --git a/chrome/browser/metrics/field_trial_synchronizer.cc b/chrome/browser/metrics/field_trial_synchronizer.cc
index 9dab6c1..906f637 100644
--- a/chrome/browser/metrics/field_trial_synchronizer.cc
+++ b/chrome/browser/metrics/field_trial_synchronizer.cc
@@ -51,7 +51,11 @@
 void FieldTrialSynchronizer::OnFieldTrialGroupFinalized(
     const std::string& field_trial_name,
     const std::string& group_name) {
+  // TODO(asvitkine): Remove these CHECKs once http://crbug.com/359406 is fixed.
   CHECK(!field_trial_name.empty() && !group_name.empty());
+  CHECK_EQ(group_name, base::FieldTrialList::FindFullName(field_trial_name))
+      << field_trial_name << ":" << group_name << "=>"
+      << base::FieldTrialList::FindFullName(field_trial_name);
   BrowserThread::PostTask(
       BrowserThread::UI, FROM_HERE,
       base::Bind(&FieldTrialSynchronizer::NotifyAllRenderers,
diff --git a/chrome/browser/net/chrome_network_delegate.cc b/chrome/browser/net/chrome_network_delegate.cc
index 8fd4f9b..b7fc936 100644
--- a/chrome/browser/net/chrome_network_delegate.cc
+++ b/chrome/browser/net/chrome_network_delegate.cc
@@ -35,6 +35,7 @@
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/task_management/task_manager_interface.h"
 #include "chrome/common/chrome_constants.h"
+#include "chrome/common/features.h"
 #include "chrome/common/pref_names.h"
 #include "components/content_settings/core/browser/cookie_settings.h"
 #include "components/data_usage/core/data_use_aggregator.h"
@@ -56,7 +57,7 @@
 #include "net/log/net_log.h"
 #include "net/url_request/url_request.h"
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
 #include "chrome/browser/io_thread.h"
 #include "chrome/browser/precache/precache_manager_factory.h"
 #include "components/precache/content/precache_manager.h"
@@ -106,7 +107,7 @@
   callback.Run(rv);
 }
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
 void RecordPrecacheStatsOnUIThread(const GURL& url,
                                    const GURL& referrer,
                                    base::TimeDelta latency,
@@ -129,7 +130,7 @@
   precache_manager->RecordStatsForFetch(url, referrer, latency, fetch_time,
                                         size, was_cached);
 }
-#endif  // defined(OS_ANDROID)
+#endif  // BUILDFLAG(ANDROID_JAVA_UI)
 
 void ReportInvalidReferrerSendOnUI() {
   base::RecordAction(
@@ -526,7 +527,7 @@
   }
 
   if (request->status().status() == net::URLRequestStatus::SUCCESS) {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
     // For better accuracy, we use the actual bytes read instead of the length
     // specified with the Content-Length header, which may be inaccurate,
     // or missing, as is the case with chunked encoding.
@@ -540,7 +541,7 @@
         base::Bind(&RecordPrecacheStatsOnUIThread, request->url(),
                    GURL(request->referrer()), latency, base::Time::Now(),
                    received_content_length, request->was_cached(), profile_));
-#endif  // defined(OS_ANDROID)
+#endif  // BUILDFLAG(ANDROID_JAVA_UI)
     extensions_delegate_->OnCompleted(request, started);
   } else if (request->status().status() == net::URLRequestStatus::FAILED ||
              request->status().status() == net::URLRequestStatus::CANCELED) {
diff --git a/chrome/browser/net/net_error_tab_helper.cc b/chrome/browser/net/net_error_tab_helper.cc
index 25b9e7a950..bc0f9a7 100644
--- a/chrome/browser/net/net_error_tab_helper.cc
+++ b/chrome/browser/net/net_error_tab_helper.cc
@@ -13,6 +13,7 @@
 #include "chrome/browser/net/net_error_diagnostics_dialog.h"
 #include "chrome/browser/platform_util.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/common/features.h"
 #include "chrome/common/localized_error.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/render_messages.h"
@@ -25,13 +26,13 @@
 #include "net/base/net_errors.h"
 #include "url/gurl.h"
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
 #include "chrome/browser/android/offline_pages/offline_page_model_factory.h"
 #include "chrome/browser/android/tab_android.h"
 #include "components/offline_pages/offline_page_feature.h"
 #include "components/offline_pages/offline_page_item.h"
 #include "components/offline_pages/offline_page_model.h"
-#endif  // defined(OS_ANDROID)
+#endif  // BUILDFLAG(ANDROID_JAVA_UI)
 
 using content::BrowserContext;
 using content::BrowserThread;
@@ -131,9 +132,9 @@
 
   is_error_page_ = is_error_page;
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
   SetOfflinePageInfo(render_frame_host, validated_url);
-#endif  // defined(OS_ANDROID)
+#endif  // BUILDFLAG(ANDROID_JAVA_UI)
 }
 
 void NetErrorTabHelper::DidCommitProvisionalLoadForFrame(
@@ -185,10 +186,10 @@
   IPC_BEGIN_MESSAGE_MAP(NetErrorTabHelper, message)
     IPC_MESSAGE_HANDLER(ChromeViewHostMsg_RunNetworkDiagnostics,
                         RunNetworkDiagnostics)
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
     IPC_MESSAGE_HANDLER(ChromeViewHostMsg_ShowOfflinePages, ShowOfflinePages)
     IPC_MESSAGE_HANDLER(ChromeViewHostMsg_LoadOfflineCopy, LoadOfflineCopy)
-#endif  // defined(OS_ANDROID)
+#endif  // BUILDFLAG(ANDROID_JAVA_UI)
     IPC_MESSAGE_UNHANDLED(handled = false)
   IPC_END_MESSAGE_MAP()
 
@@ -296,7 +297,7 @@
   ShowNetworkDiagnosticsDialog(web_contents(), sanitized_url);
 }
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
 void NetErrorTabHelper::SetOfflinePageInfo(
     content::RenderFrameHost* render_frame_host,
     const GURL& url) {
@@ -354,6 +355,6 @@
   return entry && (entry->GetPageType() == content::PAGE_TYPE_ERROR);
 }
 
-#endif  // defined(OS_ANDROID)
+#endif  // BUILDFLAG(ANDROID_JAVA_UI)
 
 }  // namespace chrome_browser_net
diff --git a/chrome/browser/net/net_error_tab_helper.h b/chrome/browser/net/net_error_tab_helper.h
index 169c81a..37dcf37 100644
--- a/chrome/browser/net/net_error_tab_helper.h
+++ b/chrome/browser/net/net_error_tab_helper.h
@@ -13,6 +13,7 @@
 #include "base/memory/weak_ptr.h"
 #include "base/prefs/pref_member.h"
 #include "chrome/browser/net/dns_probe_service.h"
+#include "chrome/common/features.h"
 #include "components/error_page/common/net_error_info.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "content/public/browser/web_contents_user_data.h"
@@ -103,13 +104,13 @@
   virtual void RunNetworkDiagnosticsHelper(const std::string& sanitized_url);
 
   // Relates to offline pages handling.
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
   void SetOfflinePageInfo(content::RenderFrameHost* render_frame_host,
                           const GURL& url);
   void ShowOfflinePages();
   void LoadOfflineCopy(const GURL& url);
   bool IsFromErrorPage() const;
-#endif  // defined(OS_ANDROID)
+#endif  // BUILDFLAG(ANDROID_JAVA_UI)
 
   // True if the last provisional load that started was for an error page.
   bool is_error_page_;
diff --git a/chrome/browser/page_load_metrics/page_load_metrics_browsertest.cc b/chrome/browser/page_load_metrics/page_load_metrics_browsertest.cc
index d56a7ec..897e062 100644
--- a/chrome/browser/page_load_metrics/page_load_metrics_browsertest.cc
+++ b/chrome/browser/page_load_metrics/page_load_metrics_browsertest.cc
@@ -6,7 +6,7 @@
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "components/page_load_metrics/browser/metrics_web_contents_observer.h"
-#include "net/test/spawned_test_server/spawned_test_server.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
 
 namespace page_load_metrics {
 
@@ -22,7 +22,7 @@
 };
 
 IN_PROC_BROWSER_TEST_F(MetricsWebContentsObserverBrowserTest, NoNavigation) {
-  ASSERT_TRUE(test_server()->Start());
+  ASSERT_TRUE(embedded_test_server()->Start());
 
   histogram_tester_.ExpectTotalCount(kHistogramDomContentLoaded, 0);
   histogram_tester_.ExpectTotalCount(kHistogramLoad, 0);
@@ -30,12 +30,12 @@
 }
 
 IN_PROC_BROWSER_TEST_F(MetricsWebContentsObserverBrowserTest, NewPage) {
-  ASSERT_TRUE(test_server()->Start());
+  ASSERT_TRUE(embedded_test_server()->Start());
 
   ui_test_utils::NavigateToURL(browser(),
-                               test_server()->GetURL("/title1.html"));
+                               embedded_test_server()->GetURL("/title1.html"));
   ui_test_utils::NavigateToURL(browser(),
-                               test_server()->GetURL("/title2.html"));
+                               embedded_test_server()->GetURL("/title2.html"));
 
   histogram_tester_.ExpectTotalCount(kHistogramDomContentLoaded, 1);
   histogram_tester_.ExpectTotalCount(kHistogramLoad, 1);
@@ -43,14 +43,14 @@
 }
 
 IN_PROC_BROWSER_TEST_F(MetricsWebContentsObserverBrowserTest, AnchorLink) {
-  ASSERT_TRUE(test_server()->Start());
+  ASSERT_TRUE(embedded_test_server()->Start());
 
   ui_test_utils::NavigateToURL(browser(),
-                               test_server()->GetURL("/title1.html"));
+                               embedded_test_server()->GetURL("/title1.html"));
+  ui_test_utils::NavigateToURL(
+      browser(), embedded_test_server()->GetURL("/title1.html#hash"));
   ui_test_utils::NavigateToURL(browser(),
-                               test_server()->GetURL("/title1.html#hash"));
-  ui_test_utils::NavigateToURL(browser(),
-                               test_server()->GetURL("/title2.html"));
+                               embedded_test_server()->GetURL("/title2.html"));
 
   histogram_tester_.ExpectTotalCount(kHistogramDomContentLoaded, 1);
   histogram_tester_.ExpectTotalCount(kHistogramLoad, 1);
diff --git a/chrome/browser/password_manager/chrome_password_manager_client.cc b/chrome/browser/password_manager/chrome_password_manager_client.cc
index 6bbdc00..bdd0a1e 100644
--- a/chrome/browser/password_manager/chrome_password_manager_client.cc
+++ b/chrome/browser/password_manager/chrome_password_manager_client.cc
@@ -22,6 +22,7 @@
 #include "chrome/browser/ui/passwords/passwords_client_ui_delegate.h"
 #include "chrome/common/channel_info.h"
 #include "chrome/common/chrome_switches.h"
+#include "chrome/common/features.h"
 #include "chrome/common/url_constants.h"
 #include "components/autofill/content/browser/content_autofill_driver.h"
 #include "components/autofill/content/browser/content_autofill_driver_factory.h"
@@ -53,11 +54,11 @@
 #include "net/base/url_util.h"
 #include "third_party/re2/re2/re2.h"
 
-#if defined(OS_MACOSX) || defined(OS_ANDROID)
+#if defined(OS_MACOSX) || BUILDFLAG(ANDROID_JAVA_UI)
 #include "chrome/browser/password_manager/save_password_infobar_delegate.h"
 #endif
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
 #include "chrome/browser/android/tab_android.h"
 #include "chrome/browser/password_manager/account_chooser_dialog_android.h"
 #include "chrome/browser/password_manager/generated_password_saved_infobar_delegate_android.h"
@@ -228,7 +229,7 @@
       manage_passwords_ui_controller->OnPasswordSubmitted(form_to_save.Pass());
     }
   } else {
-#if defined(OS_MACOSX) || defined(OS_ANDROID)
+#if defined(OS_MACOSX) || BUILDFLAG(ANDROID_JAVA_UI)
     if (form_to_save->IsBlacklisted())
       return false;
     std::string uma_histogram_suffix(
@@ -273,7 +274,7 @@
 void ChromePasswordManagerClient::NotifyUserAutoSignin(
     ScopedVector<autofill::PasswordForm> local_forms) {
   DCHECK(!local_forms.empty());
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
   ShowAutoSigninPrompt(web_contents(), local_forms[0]->username_value);
 #else
   PasswordsClientUIDelegateFromWebContents(web_contents())
@@ -284,7 +285,7 @@
 
 void ChromePasswordManagerClient::AutomaticPasswordSave(
     scoped_ptr<password_manager::PasswordFormManager> saved_form) {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
   GeneratedPasswordSavedInfoBarDelegateAndroid::Create(web_contents());
 #else
   if (IsTheHotNewBubbleUIEnabled()) {
@@ -473,7 +474,7 @@
 }
 
 bool ChromePasswordManagerClient::IsTheHotNewBubbleUIEnabled() {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
   return false;
 #elif defined(OS_MACOSX)
   // Query the group first for correct UMA reporting.
diff --git a/chrome/browser/password_manager/password_manager_browsertest.cc b/chrome/browser/password_manager/password_manager_browsertest.cc
index 2cecdc1..5cb9c09 100644
--- a/chrome/browser/password_manager/password_manager_browsertest.cc
+++ b/chrome/browser/password_manager/password_manager_browsertest.cc
@@ -1433,7 +1433,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTestBase,
-                       AutofillSuggetionsForPasswordFormWithoutUsernameField) {
+                       AutofillSuggestionsForPasswordFormWithoutUsernameField) {
   std::string submit =
       "document.getElementById('password').value = 'mypassword';"
       "document.getElementById('submit-button').click();";
@@ -1795,7 +1795,7 @@
 // Tests that if a site embeds the login and signup forms into one <form>, the
 // login form still gets autofilled.
 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTestBase,
-                       AutofillSuggetionsForLoginSignupForm) {
+                       AutofillSuggestionsForLoginSignupForm) {
   std::string submit =
       "document.getElementById('username').value = 'myusername';"
       "document.getElementById('password').value = 'mypassword';"
@@ -2261,7 +2261,7 @@
 // ambiguity in id attribute gets autofilled correctly.
 IN_PROC_BROWSER_TEST_F(
     PasswordManagerBrowserTestBase,
-    AutofillSuggetionsForPasswordFormWithAmbiguousIdAttribute) {
+    AutofillSuggestionsForPasswordFormWithAmbiguousIdAttribute) {
   // At first let us save credentials to the PasswordManager.
   scoped_refptr<password_manager::PasswordStore> password_store =
       PasswordStoreFactory::GetForProfile(browser()->profile(),
@@ -2309,7 +2309,7 @@
 // name and id attribute gets autofilled correctly.
 IN_PROC_BROWSER_TEST_F(
     PasswordManagerBrowserTestBase,
-    AutofillSuggetionsForPasswordFormWithoutNameOrIdAttribute) {
+    AutofillSuggestionsForPasswordFormWithoutNameOrIdAttribute) {
   // At first let us save credentials to the PasswordManager.
   scoped_refptr<password_manager::PasswordStore> password_store =
       PasswordStoreFactory::GetForProfile(browser()->profile(),
@@ -2356,7 +2356,7 @@
 // Test whether the change password form having username and password fields
 // without name and id attribute gets autofilled correctly.
 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTestBase,
-                       AutofillSuggetionsForChangePwdWithEmptyNames) {
+                       AutofillSuggestionsForChangePwdWithEmptyNames) {
   // At first let us save credentials to the PasswordManager.
   scoped_refptr<password_manager::PasswordStore> password_store =
       PasswordStoreFactory::GetForProfile(browser()->profile(),
@@ -2416,7 +2416,7 @@
 // correctly.
 IN_PROC_BROWSER_TEST_F(
     PasswordManagerBrowserTestBase,
-    AutofillSuggetionsForChangePwdWithEmptyNamesAndAutocomplete) {
+    AutofillSuggestionsForChangePwdWithEmptyNamesAndAutocomplete) {
   // At first let us save credentials to the PasswordManager.
   scoped_refptr<password_manager::PasswordStore> password_store =
       PasswordStoreFactory::GetForProfile(browser()->profile(),
@@ -2473,7 +2473,7 @@
 // |autocomplete='new-password'| atrribute do not get autofilled.
 IN_PROC_BROWSER_TEST_F(
     PasswordManagerBrowserTestBase,
-    AutofillSuggetionsForChangePwdWithEmptyNamesButOnlyNewPwdField) {
+    AutofillSuggestionsForChangePwdWithEmptyNamesButOnlyNewPwdField) {
   // At first let us save credentials to the PasswordManager.
   scoped_refptr<password_manager::PasswordStore> password_store =
       PasswordStoreFactory::GetForProfile(browser()->profile(),
@@ -2588,10 +2588,10 @@
 // Test whether the password form which is loaded as hidden is autofilled
 // correctly. This happens very often in situations when in order to sign-in the
 // user clicks a sign-in button and a hidden passsword form becomes visible.
-// This test differs from AutofillSuggetionsForProblematicPasswordForm in that
+// This test differs from AutofillSuggestionsForProblematicPasswordForm in that
 // the form is hidden and in that test only some fields are hidden.
 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTestBase,
-                       AutofillSuggetionsHiddenPasswordForm) {
+                       AutofillSuggestionsHiddenPasswordForm) {
   // At first let us save credentials to the PasswordManager.
   scoped_refptr<password_manager::PasswordStore> password_store =
       PasswordStoreFactory::GetForProfile(browser()->profile(),
@@ -2638,7 +2638,7 @@
 // Test whether the password form with the problematic invisible password field
 // gets autofilled correctly.
 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTestBase,
-                       AutofillSuggetionsForProblematicPasswordForm) {
+                       AutofillSuggestionsForProblematicPasswordForm) {
   // At first let us save credentials to the PasswordManager.
   scoped_refptr<password_manager::PasswordStore> password_store =
       PasswordStoreFactory::GetForProfile(browser()->profile(),
@@ -2685,7 +2685,7 @@
 // Test whether the password form with the problematic invisible password field
 // in ambiguous password form gets autofilled correctly.
 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTestBase,
-                       AutofillSuggetionsForProblematicAmbiguousPasswordForm) {
+                       AutofillSuggestionsForProblematicAmbiguousPasswordForm) {
   // At first let us save credentials to the PasswordManager.
   scoped_refptr<password_manager::PasswordStore> password_store =
       PasswordStoreFactory::GetForProfile(browser()->profile(),
@@ -2871,4 +2871,35 @@
 }
 #endif
 
+// Tests that the prompt to save the password is still shown if the fields have
+// the "autocomplete" attribute set off.
+IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTestBase,
+                       PromptForSubmitWithAutocompleteOff) {
+  NavigateToFile("/password/password_autocomplete_off_test.html");
+
+  NavigationObserver observer(WebContents());
+  scoped_ptr<PromptObserver> prompt_observer(
+      PromptObserver::Create(WebContents()));
+  std::string fill_and_submit =
+      "document.getElementById('username').value = 'temp';"
+      "document.getElementById('password').value = 'random';"
+      "document.getElementById('submit').click()";
+  ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
+  observer.Wait();
+  EXPECT_TRUE(prompt_observer->IsShowingPrompt());
+}
+
+// Tests that password suggestions still work if the fields have the
+// "autocomplete" attribute set to off.
+IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTestBase,
+                       AutofillSuggestionsForPasswordFormWithAutocompleteOff) {
+  std::string submit =
+      "document.getElementById('username').value = 'temp';"
+      "document.getElementById('password').value = 'mypassword';"
+      "document.getElementById('submit').click();";
+  VerifyPasswordIsSavedAndFilled(
+      "/password/password_autocomplete_off_test.html", submit, "password",
+      "mypassword");
+}
+
 }  // namespace password_manager
diff --git a/chrome/browser/platform_util.h b/chrome/browser/platform_util.h
index 651ae89..7a9494d9 100644
--- a/chrome/browser/platform_util.h
+++ b/chrome/browser/platform_util.h
@@ -9,6 +9,7 @@
 
 #include "base/callback_forward.h"
 #include "base/strings/string16.h"
+#include "chrome/common/features.h"
 #include "ui/gfx/native_widget_types.h"
 
 class GURL;
@@ -98,7 +99,7 @@
 bool IsSwipeTrackingFromScrollEventsEnabled();
 #endif
 
-#if defined(OS_ANDROID) && !defined(USE_AURA)
+#if BUILDFLAG(ANDROID_JAVA_UI)
 bool RegisterPlatformUtil(JNIEnv* env);
 #endif
 }  // namespace platform_util
diff --git a/chrome/browser/platform_util_aura.cc b/chrome/browser/platform_util_aura.cc
index 6ef69e57..db3a3438 100644
--- a/chrome/browser/platform_util_aura.cc
+++ b/chrome/browser/platform_util_aura.cc
@@ -13,25 +13,6 @@
 
 namespace platform_util {
 
-#if defined(OS_ANDROID)
-// TODO(bshe): We might want to use platform_util_android.cc for Aura Android.
-// See crbug.com/561664
-void ShowItemInFolder(Profile* profile, const base::FilePath& full_path) {
-  NOTIMPLEMENTED();
-}
-
-void OpenItem(Profile* profile,
-              const base::FilePath& full_path,
-              OpenItemType item_type,
-              const OpenOperationCallback& callback) {
-  NOTIMPLEMENTED();
-}
-
-void OpenExternal(Profile* profile, const GURL& url) {
-  NOTIMPLEMENTED();
-}
-#endif
-
 gfx::NativeWindow GetTopLevel(gfx::NativeView view) {
   return view->GetToplevelWindow();
 }
diff --git a/chrome/browser/policy/configuration_policy_handler_list_factory.cc b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
index 6de0567..ba44e2cb 100644
--- a/chrome/browser/policy/configuration_policy_handler_list_factory.cc
+++ b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
@@ -12,6 +12,7 @@
 #include "chrome/browser/policy/managed_bookmarks_policy_handler.h"
 #include "chrome/browser/profiles/incognito_mode_policy_handler.h"
 #include "chrome/common/chrome_switches.h"
+#include "chrome/common/features.h"
 #include "chrome/common/pref_names.h"
 #include "components/bookmarks/common/bookmark_pref_names.h"
 #include "components/content_settings/core/common/pref_names.h"
@@ -35,7 +36,7 @@
 #include "components/variations/pref_names.h"
 #include "policy/policy_constants.h"
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
 #include "chrome/browser/search/contextual_search_policy_handler_android.h"
 #endif
 
@@ -507,14 +508,14 @@
     base::Value::TYPE_BOOLEAN },
 #endif  // !defined(OS_MACOSX) && !defined(OS_CHROMEOS)
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
   { key::kDataCompressionProxyEnabled,
     data_reduction_proxy::prefs::kDataReductionProxyEnabled,
     base::Value::TYPE_BOOLEAN },
   { key::kAuthAndroidNegotiateAccountType,
     prefs::kAuthAndroidNegotiateAccountType,
     base::Value::TYPE_STRING },
-#endif  // defined(OS_ANDROID)
+#endif  // BUILDFLAG(ANDROID_JAVA_UI)
 
 #if !defined(OS_CHROMEOS) && !defined(OS_ANDROID) && !defined(OS_IOS)
   { key::kNativeMessagingUserLevelHosts,
@@ -622,7 +623,7 @@
   handlers->AddHandler(make_scoped_ptr(new ProxyPolicyHandler()));
   handlers->AddHandler(make_scoped_ptr(new URLBlacklistPolicyHandler()));
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
   handlers->AddHandler(
       make_scoped_ptr(new ContextualSearchPolicyHandlerAndroid()));
 #endif
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index ee136d2..57862ff 100644
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -66,6 +66,7 @@
 #include "chrome/browser/ui/webui/ntp/new_tab_ui.h"
 #include "chrome/browser/ui/webui/plugins_ui.h"
 #include "chrome/browser/ui/webui/print_preview/sticky_settings.h"
+#include "chrome/common/features.h"
 #include "chrome/common/pref_names.h"
 #include "components/autofill/core/browser/autofill_manager.h"
 #include "components/content_settings/core/browser/host_content_settings_map.h"
@@ -116,10 +117,8 @@
 #include "chrome/browser/signin/easy_unlock_service.h"
 #include "chrome/browser/ui/webui/extensions/extension_settings_handler.h"
 #include "extensions/browser/extension_prefs.h"
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
 #include "chrome/browser/extensions/api/copresence/copresence_api.h"
 #include "chrome/browser/ui/toolbar/toolbar_actions_bar.h"
-#endif
 #endif  // defined(ENABLE_EXTENSIONS)
 
 #if defined(ENABLE_PLUGIN_INSTALLATION)
@@ -138,7 +137,7 @@
 #include "chrome/browser/ui/webui/local_discovery/local_discovery_ui.h"
 #endif
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
 #include "chrome/browser/android/bookmarks/partner_bookmarks_shim.h"
 #include "chrome/browser/android/most_visited_sites.h"
 #include "chrome/browser/android/new_tab_page_prefs.h"
@@ -200,6 +199,7 @@
 #endif
 
 #if defined(OS_CHROMEOS) && defined(ENABLE_APP_LIST)
+#include "chrome/browser/ui/app_list/arc/arc_app_list_prefs.h"
 #include "chrome/browser/ui/app_list/google_now_extension.h"
 #endif
 
@@ -298,10 +298,18 @@
   TaskManager::RegisterPrefs(registry);
 #endif  // defined(ENABLE_TASK_MANAGER)
 
-#if !defined(OS_ANDROID)
+#if defined(ENABLE_BACKGROUND)
   BackgroundModeManager::RegisterPrefs(registry);
-  ChromeTracingDelegate::RegisterPrefs(registry);
+#endif
+
+  // TODO(bshe): Use !defined(ANDROID_JAVA_UI) once
+  // codereview.chromium.org/1459793002 landed.
+#if !defined(OS_ANDROID) || defined(USE_AURA)
   RegisterBrowserPrefs(registry);
+#endif
+
+#if !defined(OS_ANDROID)
+  ChromeTracingDelegate::RegisterPrefs(registry);
   StartupBrowserCreator::RegisterLocalStatePrefs(registry);
   // The native GCM is used on Android instead.
   gcm::GCMChannelStatusSyncer::RegisterPrefs(registry);
@@ -422,10 +430,8 @@
   extensions::launch_util::RegisterProfilePrefs(registry);
   ExtensionWebUI::RegisterProfilePrefs(registry);
   extensions::ExtensionPrefs::RegisterProfilePrefs(registry);
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
   ToolbarActionsBar::RegisterProfilePrefs(registry);
   extensions::CopresenceService::RegisterProfilePrefs(registry);
-#endif
   RegisterAnimationPolicyPrefs(registry);
 #endif  // defined(ENABLE_EXTENSIONS)
 
@@ -462,7 +468,7 @@
   SupervisedUserWhitelistService::RegisterProfilePrefs(registry);
 #endif
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
   variations::VariationsService::RegisterProfilePrefs(registry);
   MostVisitedSites::RegisterProfilePrefs(registry);
   NewTabPagePrefs::RegisterProfilePrefs(registry);
@@ -484,7 +490,9 @@
   signin::RegisterProfilePrefs(registry);
 #endif
 
-#if !defined(OS_ANDROID) && !defined(OS_CHROMEOS)
+  // TODO(bshe): Revisit this once it is more clear on what should we do with
+  // default apps on Aura Android. See crbug.com/564738
+#if (!defined(OS_ANDROID) || defined(USE_AURA)) && !defined(OS_CHROMEOS)
   default_apps::RegisterProfilePrefs(registry);
 #endif
 
@@ -503,6 +511,10 @@
   flags_ui::PrefServiceFlagsStorage::RegisterProfilePrefs(registry);
 #endif
 
+#if defined(OS_CHROMEOS) && defined(ENABLE_APP_LIST)
+  ArcAppListPrefs::RegisterProfilePrefs(registry);
+#endif
+
 #if defined(OS_WIN)
   component_updater::RegisterProfilePrefsForSwReporter(registry);
   NetworkProfileBubble::RegisterProfilePrefs(registry);
diff --git a/chrome/browser/prefs/incognito_mode_prefs.cc b/chrome/browser/prefs/incognito_mode_prefs.cc
index e3d7499..543451d 100644
--- a/chrome/browser/prefs/incognito_mode_prefs.cc
+++ b/chrome/browser/prefs/incognito_mode_prefs.cc
@@ -12,6 +12,7 @@
 #include "base/time/time.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/chrome_switches.h"
+#include "chrome/common/features.h"
 #include "chrome/common/pref_names.h"
 #include "components/pref_registry/pref_registry_syncable.h"
 #include "content/public/browser/browser_thread.h"
@@ -26,9 +27,9 @@
 #include "base/win/windows_version.h"
 #endif  // OS_WIN
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
 #include "chrome/browser/android/chrome_application.h"
-#endif  // OS_ANDROID
+#endif  // BUILDFLAG(ANDROID_JAVA_UI)
 
 using content::BrowserThread;
 
@@ -208,7 +209,12 @@
 bool IncognitoModePrefs::ArePlatformParentalControlsEnabled() {
 #if defined(OS_WIN)
   return PlatformParentalControlsValue::GetInstance()->is_enabled();
-#elif defined(OS_ANDROID)
+#elif defined(OS_ANDROID) && defined(USE_AURA)
+  // TODO(bshe): Support parental controls for Aura Android. See
+  // crbug.com/564742
+  NOTIMPLEMENTED();
+  return false;
+#elif BUILDFLAG(ANDROID_JAVA_UI)
   return chrome::android::ChromeApplication::AreParentalControlsEnabled();
 #else
   return false;
diff --git a/chrome/browser/printing/print_job_worker.cc b/chrome/browser/printing/print_job_worker.cc
index 771ce18..0b2552e 100644
--- a/chrome/browser/printing/print_job_worker.cc
+++ b/chrome/browser/printing/print_job_worker.cc
@@ -16,6 +16,7 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/printing/print_job.h"
+#include "chrome/common/features.h"
 #include "chrome/grit/generated_resources.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/notification_service.h"
@@ -27,7 +28,7 @@
 #include "printing/printing_utils.h"
 #include "ui/base/l10n/l10n_util.h"
 
-#if defined(OS_ANDROID) && !defined(USE_AURA)
+#if BUILDFLAG(ANDROID_JAVA_UI)
 #include "chrome/browser/android/tab_android.h"
 #endif
 
@@ -213,7 +214,7 @@
     bool is_scripted) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
-#if defined(OS_ANDROID) && !defined(USE_AURA)
+#if BUILDFLAG(ANDROID_JAVA_UI)
   if (is_scripted) {
     PrintingContextDelegate* printing_context_delegate =
         static_cast<PrintingContextDelegate*>(printing_context_delegate_.get());
diff --git a/chrome/browser/profile_resetter/profile_resetter.h b/chrome/browser/profile_resetter/profile_resetter.h
index 31f92cd5..e230a15 100644
--- a/chrome/browser/profile_resetter/profile_resetter.h
+++ b/chrome/browser/profile_resetter/profile_resetter.h
@@ -61,11 +61,11 @@
   // Resets |resettable_flags| and calls |callback| on the UI thread on
   // completion. |default_settings| allows the caller to specify some default
   // settings. |default_settings| shouldn't be NULL.
-  void Reset(ResettableFlags resettable_flags,
-             scoped_ptr<BrandcodedDefaultSettings> master_settings,
-             const base::Closure& callback);
+  virtual void Reset(ResettableFlags resettable_flags,
+                     scoped_ptr<BrandcodedDefaultSettings> master_settings,
+                     const base::Closure& callback);
 
-  bool IsActive() const;
+  virtual bool IsActive() const;
 
  private:
   // Marks |resettable| as done and triggers |callback_| if all pending jobs
diff --git a/chrome/browser/profiles/profile.cc b/chrome/browser/profiles/profile.cc
index 8566442..f967a254 100644
--- a/chrome/browser/profiles/profile.cc
+++ b/chrome/browser/profiles/profile.cc
@@ -79,7 +79,7 @@
       prefs::kSearchSuggestEnabled,
       true,
       user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
   registry->RegisterStringPref(
       prefs::kContextualSearchEnabled,
       std::string(),
diff --git a/chrome/browser/profiles/profile_io_data.cc b/chrome/browser/profiles/profile_io_data.cc
index e581281..d4f4c98f 100644
--- a/chrome/browser/profiles/profile_io_data.cc
+++ b/chrome/browser/profiles/profile_io_data.cc
@@ -47,6 +47,7 @@
 #include "chrome/browser/ui/search/new_tab_page_interceptor_service_factory.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/chrome_switches.h"
+#include "chrome/common/features.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/url_constants.h"
 #include "components/about_handler/about_protocol_handler.h"
@@ -867,7 +868,7 @@
 
 void ProfileIOData::InitializeMetricsEnabledStateOnUIThread() {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
   // TODO(dwkang): rename or unify the pref for UMA once we have conclusion
   // in crbugs.com/246495.
   // Android has it's own preferences for metrics / crash uploading.
@@ -882,7 +883,7 @@
                        g_browser_process->local_state());
   enable_metrics_.MoveToThread(
       BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO));
-#endif  // defined(OS_ANDROID)
+#endif  // BUILDFLAG(ANDROID_JAVA_UI)
 }
 
 bool ProfileIOData::GetMetricsEnabledStateOnIOThread() const {
diff --git a/chrome/browser/push_messaging/push_messaging_browsertest.cc b/chrome/browser/push_messaging/push_messaging_browsertest.cc
index 6e21fb0..a768787 100644
--- a/chrome/browser/push_messaging/push_messaging_browsertest.cc
+++ b/chrome/browser/push_messaging/push_messaging_browsertest.cc
@@ -79,7 +79,9 @@
 
   // InProcessBrowserTest:
   void SetUpCommandLine(base::CommandLine* command_line) override {
-    command_line->AppendSwitch(switches::kEnablePushMessagePayload);
+    command_line->AppendSwitch(
+        switches::kEnableExperimentalWebPlatformFeatures);
+
     InProcessBrowserTest::SetUpCommandLine(command_line);
   }
 
diff --git a/chrome/browser/push_messaging/push_messaging_notification_manager.cc b/chrome/browser/push_messaging/push_messaging_notification_manager.cc
index 88e0aa1..e5ec50aa 100644
--- a/chrome/browser/push_messaging/push_messaging_notification_manager.cc
+++ b/chrome/browser/push_messaging/push_messaging_notification_manager.cc
@@ -13,6 +13,7 @@
 #include "chrome/browser/notifications/platform_notification_service_impl.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/push_messaging/push_messaging_constants.h"
+#include "chrome/common/features.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/grit/generated_resources.h"
 #include "components/rappor/rappor_utils.h"
@@ -29,7 +30,7 @@
 #include "ui/base/l10n/l10n_util.h"
 #include "url/gurl.h"
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
 #include "chrome/browser/ui/android/tab_model/tab_model.h"
 #include "chrome/browser/ui/android/tab_model/tab_model_list.h"
 #else
@@ -144,7 +145,7 @@
   bool notification_needed = true;
 
   // Sites with a currently visible tab don't need to show notifications.
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
   for (auto it = TabModelList::begin(); it != TabModelList::end(); ++it) {
     Profile* profile = (*it)->GetProfile();
     WebContents* active_web_contents = (*it)->GetActiveWebContents();
@@ -158,11 +159,7 @@
       notification_needed = false;
       break;
     }
-#if defined(OS_ANDROID)
   }
-#else
-  }
-#endif
 
   // If more than one notification is showing for this Service Worker, close
   // the default notification if it happens to be part of this group.
diff --git a/chrome/browser/push_messaging/push_messaging_service_impl.cc b/chrome/browser/push_messaging/push_messaging_service_impl.cc
index e1333d23..c26b3b5 100644
--- a/chrome/browser/push_messaging/push_messaging_service_impl.cc
+++ b/chrome/browser/push_messaging/push_messaging_service_impl.cc
@@ -754,7 +754,7 @@
 
 bool PushMessagingServiceImpl::AreMessagePayloadsEnabled() const {
   return base::CommandLine::ForCurrentProcess()->HasSwitch(
-      switches::kEnablePushMessagePayload);
+      switches::kEnableExperimentalWebPlatformFeatures);
 }
 
 gcm::GCMDriver* PushMessagingServiceImpl::GetGCMDriver() const {
diff --git a/chrome/browser/push_messaging/push_messaging_service_unittest.cc b/chrome/browser/push_messaging/push_messaging_service_unittest.cc
index 22edd632..52a7069d 100644
--- a/chrome/browser/push_messaging/push_messaging_service_unittest.cc
+++ b/chrome/browser/push_messaging/push_messaging_service_unittest.cc
@@ -95,7 +95,7 @@
 
     // Force-enable encrypted payloads for incoming push messages.
     base::CommandLine::ForCurrentProcess()->AppendSwitch(
-        switches::kEnablePushMessagePayload);
+        switches::kEnableExperimentalWebPlatformFeatures);
   }
 
   ~PushMessagingServiceTest() override {}
diff --git a/chrome/browser/renderer_context_menu/render_view_context_menu_browsertest.cc b/chrome/browser/renderer_context_menu/render_view_context_menu_browsertest.cc
index d1a19c8..7c4f707f 100644
--- a/chrome/browser/renderer_context_menu/render_view_context_menu_browsertest.cc
+++ b/chrome/browser/renderer_context_menu/render_view_context_menu_browsertest.cc
@@ -476,8 +476,8 @@
   ui_test_utils::WindowedTabAddedNotificationObserver tab_observer(
       content::NotificationService::AllSources());
 
-  ASSERT_TRUE(test_server()->Start());
-  GURL url(test_server()->GetURL(std::string()));
+  ASSERT_TRUE(embedded_test_server()->Start());
+  GURL url(embedded_test_server()->GetURL("/"));
 
   scoped_ptr<TestRenderViewContextMenu> menu(
       CreateContextMenuMediaTypeNone(url, url));
diff --git a/chrome/browser/renderer_host/chrome_render_message_filter.cc b/chrome/browser/renderer_host/chrome_render_message_filter.cc
index 75f77c05..d4ad767 100644
--- a/chrome/browser/renderer_host/chrome_render_message_filter.cc
+++ b/chrome/browser/renderer_host/chrome_render_message_filter.cc
@@ -35,10 +35,6 @@
 #include "extensions/common/manifest_handlers/default_locale_handler.h"
 #endif
 
-#if defined(USE_TCMALLOC)
-#include "chrome/browser/browser_about_handler.h"
-#endif
-
 using content::BrowserThread;
 using blink::WebCache;
 
diff --git a/chrome/browser/renderer_host/chrome_resource_dispatcher_host_delegate.cc b/chrome/browser/renderer_host/chrome_resource_dispatcher_host_delegate.cc
index 351d35a9..f552005 100644
--- a/chrome/browser/renderer_host/chrome_resource_dispatcher_host_delegate.cc
+++ b/chrome/browser/renderer_host/chrome_resource_dispatcher_host_delegate.cc
@@ -25,7 +25,6 @@
 #include "chrome/browser/prerender/prerender_util.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_io_data.h"
-#include "chrome/browser/renderer_host/data_reduction_proxy_resource_throttle_android.h"
 #include "chrome/browser/renderer_host/safe_browsing_resource_throttle.h"
 #include "chrome/browser/renderer_host/thread_hop_resource_throttle.h"
 #include "chrome/browser/safe_browsing/safe_browsing_service.h"
@@ -33,6 +32,7 @@
 #include "chrome/browser/tab_contents/tab_util.h"
 #include "chrome/browser/ui/login/login_prompt.h"
 #include "chrome/common/chrome_switches.h"
+#include "chrome/common/features.h"
 #include "chrome/common/url_constants.h"
 #include "components/content_settings/core/browser/host_content_settings_map.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.h"
@@ -88,8 +88,12 @@
 #include "third_party/protobuf/src/google/protobuf/repeated_field.h"
 #endif
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
 #include "chrome/browser/android/intercept_download_resource_throttle.h"
+#endif
+
+#if defined(OS_ANDROID)
+#include "chrome/browser/renderer_host/data_reduction_proxy_resource_throttle_android.h"
 #include "components/navigation_interception/intercept_navigation_delegate.h"
 #endif
 
@@ -424,7 +428,7 @@
     throttles->push_back(new DownloadResourceThrottle(
         download_request_limiter_, info->GetWebContentsGetterForRequest(),
         request->url(), request->method()));
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
     throttles->push_back(
         new chrome::InterceptDownloadResourceThrottle(
             request, child_id, route_id, request_id));
diff --git a/chrome/browser/resources/chromeos/login/header_bar.html b/chrome/browser/resources/chromeos/login/header_bar.html
index c6cd2fd..40ec8aca 100644
--- a/chrome/browser/resources/chromeos/login/header_bar.html
+++ b/chrome/browser/resources/chromeos/login/header_bar.html
@@ -35,10 +35,4 @@
     <button id="cancel-multiple-sign-in-button" class="custom-appearance"
         i18n-content="cancel"></button>
   </div>
-  <div id="cancel-consumer-management-enrollment" class="header-bar-item"
-      hidden>
-    <button id="cancel-consumer-management-enrollment-button"
-        class="custom-appearance" i18n-content="cancel">
-    </button>
-  </div>
 </div>
diff --git a/chrome/browser/resources/chromeos/login/header_bar.js b/chrome/browser/resources/chromeos/login/header_bar.js
index d9668e1..524e5ac 100644
--- a/chrome/browser/resources/chromeos/login/header_bar.js
+++ b/chrome/browser/resources/chromeos/login/header_bar.js
@@ -62,9 +62,6 @@
           this.handleSignoutClick_);
       $('cancel-multiple-sign-in-button').addEventListener('click',
           this.handleCancelMultipleSignInClick_);
-      $('cancel-consumer-management-enrollment-button').addEventListener(
-          'click',
-          this.handleCancelConsumerManagementEnrollmentClick_);
       this.addSupervisedUserMenu.addEventListener('click',
           this.handleAddSupervisedUserClick_.bind(this));
       if (Oobe.getInstance().displayType == DISPLAY_TYPE.LOGIN ||
@@ -214,16 +211,6 @@
     },
 
     /**
-     * Cancel consumer management enrollment button handler.
-     *
-     * @private
-     */
-    handleCancelConsumerManagementEnrollmentClick_: function(e) {
-      chrome.send('cancelConsumerManagementEnrollment');
-      e.stopPropagation();
-    },
-
-    /**
      * If true then "Browse as Guest" button is shown.
      *
      * @type {boolean}
@@ -300,8 +287,6 @@
           (this.signinUIState_ == SIGNIN_UI_STATE.WRONG_HWID_WARNING);
       var isSamlPasswordConfirm =
           (this.signinUIState_ == SIGNIN_UI_STATE.SAML_PASSWORD_CONFIRM);
-      var isEnrollingConsumerManagement = (this.signinUIState_ ==
-          SIGNIN_UI_STATE.CONSUMER_MANAGEMENT_ENROLLMENT);
       var isPasswordChangedUI =
           (this.signinUIState_ == SIGNIN_UI_STATE.PASSWORD_CHANGED);
       var isMultiProfilesUI =
@@ -340,8 +325,6 @@
       $('apps-header-bar-item').hidden = !this.hasApps_ ||
           (!gaiaIsActive && !accountPickerIsActive);
       $('cancel-multiple-sign-in-item').hidden = !isMultiProfilesUI;
-      $('cancel-consumer-management-enrollment').hidden =
-          !isEnrollingConsumerManagement;
 
       if (!Oobe.getInstance().newKioskUI) {
         if (!$('apps-header-bar-item').hidden)
diff --git a/chrome/browser/resources/chromeos/login/screen_gaia_signin.js b/chrome/browser/resources/chromeos/login/screen_gaia_signin.js
index 7abcaf4..1c7d517 100644
--- a/chrome/browser/resources/chromeos/login/screen_gaia_signin.js
+++ b/chrome/browser/resources/chromeos/login/screen_gaia_signin.js
@@ -57,13 +57,6 @@
     email: '',
 
     /**
-     * Whether consumer management enrollment is in progress.
-     * @type {boolean}
-     * @private
-     */
-    isEnrollingConsumerManagement_: false,
-
-    /**
      * Timer id of pending load.
      * @type {number}
      * @private
@@ -438,10 +431,7 @@
     onBeforeShow: function(data) {
       chrome.send('loginUIStateChanged', ['gaia-signin', true]);
       $('progress-dots').hidden = true;
-      $('login-header-bar').signinUIState =
-          this.isEnrollingConsumerManagement_ ?
-              SIGNIN_UI_STATE.CONSUMER_MANAGEMENT_ENROLLMENT :
-              SIGNIN_UI_STATE.GAIA_SIGNIN;
+      $('login-header-bar').signinUIState = SIGNIN_UI_STATE.GAIA_SIGNIN;
 
       // Ensure that GAIA signin (or loading UI) is actually visible.
       window.requestAnimationFrame(function() {
@@ -545,8 +535,6 @@
       this.isShowUsers_ = data.isShowUsers;
       this.updateControlsState();
 
-      this.isEnrollingConsumerManagement_ = data.isEnrollingConsumerManagement;
-
       this.classList.toggle('full-width', false);
       if (Oobe.getInstance().currentScreen === this)
         Oobe.getInstance().updateScreenSize(this);
diff --git a/chrome/browser/resources/md_extensions/compiled_resources.gyp b/chrome/browser/resources/md_extensions/compiled_resources.gyp
index 50f7a41f..868cae3 100644
--- a/chrome/browser/resources/md_extensions/compiled_resources.gyp
+++ b/chrome/browser/resources/md_extensions/compiled_resources.gyp
@@ -13,6 +13,7 @@
           '../../../../ui/webui/resources/js/cr.js',
           '../../../../ui/webui/resources/js/i18n_behavior.js',
           'item.js',
+          'item_list.js',
           'manager.js',
           'service.js',
           'sidebar.js',
diff --git a/chrome/browser/resources/md_extensions/item.js b/chrome/browser/resources/md_extensions/item.js
index 547b074..6b9652d 100644
--- a/chrome/browser/resources/md_extensions/item.js
+++ b/chrome/browser/resources/md_extensions/item.js
@@ -25,9 +25,6 @@
      */
     setItemAllowedIncognito: assertNotReached,
 
-    /** @return {boolean} */
-    isInDevMode: assertNotReached,
-
     /**
      * @param {string} id,
      * @param {chrome.developerPrivate.ExtensionView} view
@@ -72,17 +69,6 @@
       'observeIdVisibility_(inDevMode, showingDetails_, data.id)',
     ],
 
-    /**
-     * @param {!chrome.developerPrivate.ExtensionInfo} data
-     * @param {!extensions.ItemDelegate} delegate
-     */
-    factoryImpl: function(data, delegate) {
-      this.data = data;
-      this.id = data.id;
-      this.delegate_ = delegate;
-      this.inDevMode = delegate.isInDevMode();
-    },
-
     /** @private */
     observeIdVisibility_: function(inDevMode, showingDetails, id) {
       Polymer.dom.flush();
@@ -91,6 +77,7 @@
         assert(this.data);
         idElement.innerHTML = this.i18n('itemId', this.data.id);
       }
+      this.fire('extension-item-size-changed', {item: this.data});
     },
 
     /** @private */
@@ -100,22 +87,22 @@
 
     /** @private */
     onDeleteTap_: function() {
-      this.delegate_.deleteItem(this.data.id);
+      this.delegate.deleteItem(this.data.id);
     },
 
     /** @private */
     onEnableChange_: function() {
-      this.delegate_.setItemEnabled(this.data.id, this.$.enabled.checked);
+      this.delegate.setItemEnabled(this.data.id, this.$.enabled.checked);
     },
 
     /** @private */
     onDetailsTap_: function() {
-      this.delegate_.showItemDetails(this.data.id);
+      this.delegate.showItemDetails(this.data.id);
     },
 
     /** @private */
     onAllowIncognitoChange_: function() {
-      this.delegate_.setItemAllowedIncognito(
+      this.delegate.setItemAllowedIncognito(
           this.data.id, this.$$('#allow-incognito').checked);
     },
 
@@ -124,7 +111,7 @@
      * @private
      */
     onInspectTap_: function(e) {
-      this.delegate_.inspectItemView(this.data.id, e.model.item);
+      this.delegate.inspectItemView(this.data.id, e.model.item);
     },
 
     /**
diff --git a/chrome/browser/resources/md_extensions/item_list.css b/chrome/browser/resources/md_extensions/item_list.css
new file mode 100644
index 0000000..9163291
--- /dev/null
+++ b/chrome/browser/resources/md_extensions/item_list.css
@@ -0,0 +1,15 @@
+/* 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. */
+
+h2 {
+  color: #5a5a5a;
+  font-size: 1.1em;
+  font-weight: normal;
+  margin-bottom: 0;
+  margin-top: 30px;
+}
+
+.wrapper {
+  padding: 10px 0;
+}
diff --git a/chrome/browser/resources/md_extensions/item_list.html b/chrome/browser/resources/md_extensions/item_list.html
new file mode 100644
index 0000000..1d8958a
--- /dev/null
+++ b/chrome/browser/resources/md_extensions/item_list.html
@@ -0,0 +1,21 @@
+<link rel="import" href="chrome://resources/html/cr.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/iron-list/iron-list.html">
+<link rel="import" href="chrome://extensions/item.html">
+
+<dom-module id="extensions-item-list">
+  <template>
+    <h2>[[header]]</h2>
+    <iron-list id="list" items="[[items]]" as="item">
+      <template>
+        <div class="wrapper">
+          <extensions-item data="[[item]]" delegate="[[delegate]]"
+              id="[[item.id]]" in-dev-mode="[[inDevMode]]">
+          </extensions-item>
+        </div>
+      </template>
+    </iron-list>
+  </template>
+  <link rel="import" type="css" href="chrome://extensions/item_list.css">
+  <script src="chrome://extensions/item_list.js"></script>
+</dom-module>
diff --git a/chrome/browser/resources/md_extensions/item_list.js b/chrome/browser/resources/md_extensions/item_list.js
new file mode 100644
index 0000000..f94f885
--- /dev/null
+++ b/chrome/browser/resources/md_extensions/item_list.js
@@ -0,0 +1,42 @@
+// 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.
+
+cr.define('extensions', function() {
+  var ItemList = Polymer({
+    is: 'extensions-item-list',
+
+    properties: {
+      /** @type {Array<!chrome.developerPrivate.ExtensionInfo>} */
+      items: Array,
+
+      /** @type {extensions.ItemDelegate} */
+      delegate: Object,
+
+      header: String,
+
+      inDevMode: {
+        type: Boolean,
+        value: false,
+      },
+    },
+
+    listeners: {
+      'list.extension-item-size-changed': 'itemSizeChanged_',
+    },
+
+    /**
+     * Updates the size for a given item.
+     * @param {CustomEvent} e
+     * @private
+     * @suppress {checkTypes} Closure doesn't know $.list is an IronList.
+     */
+    itemSizeChanged_: function(e) {
+      this.$.list.updateSizeForItem(e.detail.item);
+    },
+  });
+
+  return {
+    ItemList: ItemList,
+  };
+});
diff --git a/chrome/browser/resources/md_extensions/manager.css b/chrome/browser/resources/md_extensions/manager.css
index a5f689f7..d49f69c 100644
--- a/chrome/browser/resources/md_extensions/manager.css
+++ b/chrome/browser/resources/md_extensions/manager.css
@@ -14,19 +14,12 @@
 
 #items {
   -webkit-margin-start: 30px;
+  height: 100%;
   overflow-y: auto;
   padding-bottom: 30px;
-}
-
-#items h2 {
-  color: #5a5a5a;
-  font-size: 1.1em;
-  font-weight: normal;
-  margin-bottom: 0;
-  margin-top: 30px;
+  width: 100%;
 }
 
 extensions-item {
   display: inline-block;
-  margin-top: 20px;
 }
diff --git a/chrome/browser/resources/md_extensions/manager.html b/chrome/browser/resources/md_extensions/manager.html
index bfcb918..2dd99ba 100644
--- a/chrome/browser/resources/md_extensions/manager.html
+++ b/chrome/browser/resources/md_extensions/manager.html
@@ -1,7 +1,8 @@
 <link rel="import" href="chrome://resources/html/cr.html">
+<link rel="import" href="chrome://resources/html/i18n_behavior.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-header-panel/paper-header-panel.html">
-<link rel="import" href="chrome://extensions/item.html">
+<link rel="import" href="chrome://extensions/item_list.html">
 <link rel="import" href="chrome://extensions/service.html">
 <link rel="import" href="chrome://extensions/sidebar.html">
 <link rel="import" href="chrome://extensions/toolbar.html">
@@ -11,14 +12,20 @@
     <paper-header-panel id="panel">
       <extensions-toolbar class="paper-header" id="toolbar">
       </extensions-toolbar>
-      <extensions-sidebar></extensions-sidebar>
+      <extensions-sidebar in-dev-mode="[[inDevMode]]"></extensions-sidebar>
       <div id="items">
-        <h2 id="extensions-header" i18n-content="sidebarExtensions"></h2>
-        <div id="extensions-list"></div>
-        <h2 id="apps-header" i18n-content="sidebarApps"></h2>
-        <div id="apps-list"></div>
-        <h2 id="websites-header" i18n-content="sidebarWebsites"></h2>
-        <div id="websites-list"></div>
+        <extensions-item-list id="extensions-list" items="[[extensions]]"
+            delegate="[[service]]" header="[[i18n('sidebarExtensions')]]"
+            in-dev-mode="[[inDevMode]]">
+        </extensions-item-list>
+        <extensions-item-list id="apps-list" items="[[apps]]"
+            delegate="[[service]]" header="[[i18n('sidebarApps')]]"
+            in-dev-mode="[[inDevMode]]">
+        </extensions-item-list>
+        <extensions-item-list id="websites-list" items="[[websites]]"
+            delegate="[[service]]" header="[[i18n('sidebarWebsites')]]"
+            in-dev-mode="[[inDevMode]]">
+        </extensions-item-list>
       </div>
     </paper-header-panel>
   </template>
diff --git a/chrome/browser/resources/md_extensions/manager.js b/chrome/browser/resources/md_extensions/manager.js
index 0c5a2c3..417b5aa3 100644
--- a/chrome/browser/resources/md_extensions/manager.js
+++ b/chrome/browser/resources/md_extensions/manager.js
@@ -34,39 +34,66 @@
 
     properties: {
       /** @type {extensions.Sidebar} */
-      sidebar: {
-        type: Object,
-      }
+      sidebar: Object,
+
+      /** @type {extensions.Service} */
+      service: Object,
+
+      inDevMode: {
+        type: Boolean,
+        value: false,
+      },
+
+      /** @type {!Array<!chrome.developerPrivate.ExtensionInfo>} */
+      extensions: {
+        type: Array,
+        value: function() { return []; },
+      },
+
+      /** @type {!Array<!chrome.developerPrivate.ExtensionInfo>} */
+      apps: {
+        type: Array,
+        value: function() { return []; },
+      },
+
+      /** @type {!Array<!chrome.developerPrivate.ExtensionInfo>} */
+      websites: {
+        type: Array,
+        value: function() { return []; },
+      },
     },
 
+    behaviors: [
+      I18nBehavior,
+    ],
+
     ready: function() {
       /** @type {extensions.Sidebar} */
       this.sidebar = this.$$('extensions-sidebar');
-      extensions.Service.getInstance().managerReady(this);
+      this.service = extensions.Service.getInstance();
+      this.service.managerReady(this);
       this.sidebar.setScrollDelegate(new ScrollHelper(this));
     },
 
     /**
-     * Creates and adds a new extensions-item element to the list, inserting it
-     * into its sorted position in the relevant section.
-     * @param {!chrome.developerPrivate.ExtensionInfo} extension The extension
-     *     the item is representing.
-     * @param {!extensions.ItemDelegate} delegate The delegate for the item.
+     * @param {chrome.developerPrivate.ExtensionType} type The type of item.
+     * @return {string} The ID of the list that the item belongs in.
+     * @private
      */
-    addItem: function(extension, delegate) {
+    getListId_: function(type) {
       var listId;
       var ExtensionType = chrome.developerPrivate.ExtensionType;
-      switch (extension.type) {
+      switch (type) {
         case ExtensionType.HOSTED_APP:
         case ExtensionType.LEGACY_PACKAGED_APP:
-          listId = 'websites-list';
+          listId = 'websites';
           break;
         case ExtensionType.PLATFORM_APP:
-          listId = 'apps-list';
+          listId = 'apps';
           break;
         case ExtensionType.EXTENSION:
         case ExtensionType.SHARED_MODULE:
-          listId = 'extensions-list';
+          listId = 'extensions';
           break;
         case ExtensionType.THEME:
           assertNotReached(
@@ -74,41 +101,62 @@
           break;
       }
       assert(listId);
-      var extensionItem = new extensions.Item(extension, delegate);
-      var itemList = this.$[listId];
+      return listId;
+    },
 
-      var insertBeforeChild = Array.prototype.find.call(itemList.children,
-                                                        function(item) {
-        return compareExtensions(item.data, extension) > 0;
+    /**
+     * @param {string} listId The list to look for the item in.
+     * @param {string} itemId The id of the item to look for.
+     * @return {number} The index of the item in the list, or -1 if not found.
+     * @private
+     */
+    getIndexInList_: function(listId, itemId) {
+      return this[listId].findIndex(function(item) {
+        return item.id == itemId;
       });
-      itemList.insertBefore(extensionItem, insertBeforeChild);
     },
 
     /**
-     * @param {string} id The id of the extension to get the item for.
-     * @return {?extensions.Item}
+     * Creates and adds a new extensions-item element to the list, inserting it
+     * into its sorted position in the relevant section.
+     * @param {!chrome.developerPrivate.ExtensionInfo} item The extension
+     *     the new element is representing.
      */
-    getItem: function(id) {
-      return this.$$('#' + id);
-    },
-
-    /** @param {string} id The id of the item to remove. */
-    removeItem: function(id) {
-      var item = this.getItem(id);
-      if (item)
-        item.parentNode.removeChild(item);
+    addItem: function(item) {
+      var listId = this.getListId_(item.type);
+      // We should never try and add an existing item.
+      assert(this.getIndexInList_(listId, item.id) == -1);
+      var insertBeforeChild = this[listId].findIndex(function(listEl) {
+        return compareExtensions(listEl, item) > 0;
+      });
+      if (insertBeforeChild == -1)
+        insertBeforeChild = this[listId].length;
+      this.splice(listId, insertBeforeChild, 0, item);
     },
 
     /**
-     * Applies a function to each item present in the DOM.
-     * @param {!function(extensions.Item):void} callback The function to apply.
+     * @param {!chrome.developerPrivate.ExtensionInfo} item The data for the
+     *     item to update.
      */
-    forEachItem: function(callback) {
-      Array.prototype.forEach.call(
-          /** @type {Array<extensions.Item>} */(
-              Polymer.dom(this.root).querySelectorAll('extensions-item')),
-          callback);
-     },
+    updateItem: function(item) {
+      var listId = this.getListId_(item.type);
+      var index = this.getIndexInList_(listId, item.id);
+      // We should never try and update a non-existent item.
+      assert(index >= 0);
+      this.set([listId, index], item);
+    },
+
+    /**
+     * @param {!chrome.developerPrivate.ExtensionInfo} item The data for the
+     *     item to remove.
+     */
+    removeItem: function(item) {
+      var listId = this.getListId_(item.type);
+      var index = this.getIndexInList_(listId, item.id);
+      // We should never try and remove a non-existent item.
+      assert(index >= 0);
+      this.splice(listId, index, 1);
+    },
   });
 
   /**
diff --git a/chrome/browser/resources/md_extensions/service.js b/chrome/browser/resources/md_extensions/service.js
index cc4d824..a083720 100644
--- a/chrome/browser/resources/md_extensions/service.js
+++ b/chrome/browser/resources/md_extensions/service.js
@@ -33,7 +33,7 @@
         /** @private {Array<chrome.developerPrivate.ExtensionInfo>} */
         this.extensions_ = extensions;
         for (let extension of extensions)
-          this.manager_.addItem(extension, this);
+          this.manager_.addItem(extension);
       }.bind(this));
       chrome.developerPrivate.getProfileConfiguration(
           this.onProfileStateChanged_.bind(this));
@@ -46,10 +46,7 @@
     onProfileStateChanged_: function(profileInfo) {
       /** @private {chrome.developerPrivate.ProfileInfo} */
       this.profileInfo_ = profileInfo;
-      this.sidebar_.inDevMode = profileInfo.inDeveloperMode;
-      this.manager_.forEachItem(function(item) {
-        item.inDevMode = profileInfo.inDeveloperMode;
-      });
+      this.manager_.set('inDevMode', profileInfo.inDeveloperMode);
     },
 
     /**
@@ -57,6 +54,10 @@
      * @private
      */
     onItemStateChanged_: function(eventData) {
+      var currentIndex = this.extensions_.findIndex(function(extension) {
+        return extension.id == eventData.item_id;
+      });
+
       var EventType = chrome.developerPrivate.EventType;
       switch (eventData.event_type) {
         case EventType.VIEW_REGISTERED:
@@ -73,27 +74,17 @@
           if (!eventData.extensionInfo)
             break;
 
-          var existing = this.manager_.getItem(eventData.extensionInfo.id);
-          if (existing) {
-            existing.data = eventData.extensionInfo;
+          if (currentIndex >= 0) {
+            this.extensions_[currentIndex] = eventData.extensionInfo;
+            this.manager_.updateItem(eventData.extensionInfo);
           } else {
-            // If there's no existing item in the list, there shouldn't be an
-            // extension with the same id in the data.
-            var currentIndex = this.extensions_.findIndex(function(extension) {
-              return extension.id == eventData.extensionInfo.id;
-            });
-            assert(currentIndex == -1);
-
             this.extensions_.push(eventData.extensionInfo);
-            this.manager_.addItem(eventData.extensionInfo, this);
+            this.manager_.addItem(eventData.extensionInfo);
           }
           break;
         case EventType.UNINSTALLED:
-          var currentIndex = this.extensions_.findIndex(function(extension) {
-            return extension.id == eventData.item_id;
-          });
+          this.manager_.removeItem(this.extensions_[currentIndex]);
           this.extensions_.splice(currentIndex, 1);
-          this.manager_.removeItem(eventData.item_id);
           break;
         default:
           assertNotReached();
@@ -131,13 +122,6 @@
     },
 
     /** @override */
-    isInDevMode: function() {
-      // It's possible this could be called before the profileInfo is
-      // initialized; that's fine, because we'll update the items when it is.
-      return !!this.profileInfo_ && this.profileInfo_.inDeveloperMode;
-    },
-
-    /** @override */
     inspectItemView: function(id, view) {
       chrome.developerPrivate.openDevTools({
         extensionId: id,
diff --git a/chrome/browser/resources/media_router/elements/media_router_container/media_router_container.css b/chrome/browser/resources/media_router/elements/media_router_container/media_router_container.css
index 6bf24425..5a5f09f 100644
--- a/chrome/browser/resources/media_router/elements/media_router_container/media_router_container.css
+++ b/chrome/browser/resources/media_router/elements/media_router_container/media_router_container.css
@@ -77,11 +77,6 @@
   padding-top: 4px;
 }
 
-.route {
-  color: rgb(150, 150, 150);
-  padding-top: 8px;
-}
-
 #searching-devices-spinner {
   height: 30px;
   width: 30px;
@@ -100,6 +95,11 @@
   font-weight: normal;
 }
 
+.sink-subtext {
+  color: rgb(150, 150, 150);
+  padding-top: 8px;
+}
+
 .sink-text {
   -webkit-padding-end: 26px;
   line-height: normal;
@@ -111,4 +111,4 @@
 
 #route-details {
   margin-top: var(--container-header-height);
-}
\ No newline at end of file
+}
diff --git a/chrome/browser/resources/media_router/elements/media_router_container/media_router_container.html b/chrome/browser/resources/media_router/elements/media_router_container/media_router_container.html
index f3c93a3c..3fc7746b 100644
--- a/chrome/browser/resources/media_router/elements/media_router_container/media_router_container.html
+++ b/chrome/browser/resources/media_router/elements/media_router_container/media_router_container.html
@@ -89,10 +89,12 @@
                 <div class="sink-text">
                   <span>[[item.name]]</span>
                 </div>
-                <div class="sink-text route"
-                    hidden$="[[computeRouteInSinkListHidden_(item.id, sinkToRouteMap_)]]">
-                  <span>[[computeRouteInSinkListValue_(item.id, sinkToRouteMap_)]]</span>
-                </div>
+                <template is="dom-if"
+                    if="[[!computeSinkSubtextHidden_(item, sinkToRouteMap_)]]">
+                  <div class="sink-text sink-subtext">
+                    <span>[[computeSinkSubtext_(item, sinkToRouteMap_)]]</span>
+                  </div>
+                </template>
               </div>
             </div>
           </paper-item>
diff --git a/chrome/browser/resources/media_router/elements/media_router_container/media_router_container.js b/chrome/browser/resources/media_router/elements/media_router_container/media_router_container.js
index 9424143..f88b92f 100644
--- a/chrome/browser/resources/media_router/elements/media_router_container/media_router_container.js
+++ b/chrome/browser/resources/media_router/elements/media_router_container/media_router_container.js
@@ -390,27 +390,6 @@
   },
 
   /**
-   * @param {!string} sinkId A sink ID.
-   * @return {boolean} Whether or not to hide the route info in the sink list
-   *     that is associated with |sinkId|.
-   * @private
-   */
-  computeRouteInSinkListHidden_: function(sinkId, sinkToRouteMap) {
-    return !sinkToRouteMap[sinkId];
-  },
-
-  /**
-   * @param {!string} sinkId A sink ID.
-   * @return {string} The description value of the route associated with
-   *     |sinkId|.
-   * @private
-   */
-  computeRouteInSinkListValue_: function(sinkId, sinkToRouteMap) {
-    var route = sinkToRouteMap[sinkId];
-    return route ? route.description : '';
-  },
-
-  /**
    * @param {!Array<!media_router.CastMode>} castModeList The current list of
    *     cast modes.
    * @return {boolean} Whether or not to hide the share screen subheading text.
@@ -487,6 +466,38 @@
   },
 
   /**
+   * Returns the subtext to be shown for |sink|. Only called if
+   * |computeSinkSubtextHidden_| returns false for the same |sink| and
+   * |sinkToRouteMap|.
+   * @param {!media_router.Sink} sink
+   * @param {!Object<!string, ?media_router.Route>} sinkToRouteMap
+   * @return {string} The subtext to be shown.
+   * @private
+   */
+  computeSinkSubtext_: function(sink, sinkToRouteMap) {
+    var route = sinkToRouteMap[sink.id];
+    if (route && !this.isEmptyOrWhitespace_(route.description))
+      return route.description;
+
+    return sink.description;
+  },
+
+  /**
+   * Returns whether the sink subtext for |sink| should be hidden.
+   * @param {!media_router.Sink} sink
+   * @param {!Object<!string, ?media_router.Route>} sinkToRouteMap
+   * @return {boolean} |true| if the subtext should be hidden.
+   * @private
+   */
+  computeSinkSubtextHidden_: function(sink, sinkToRouteMap) {
+    if (!this.isEmptyOrWhitespace_(sink.description))
+      return false;
+
+    var route = sinkToRouteMap[sink.id];
+    return !route || this.isEmptyOrWhitespace_(route.description);
+  },
+
+  /**
    * @param {boolean} justOpened Whether the MR UI was just opened.
    * @return {boolean} Whether or not to hide the spinner.
    * @private
@@ -527,6 +538,16 @@
   },
 
   /**
+   * Returns whether given string is null, empty, or whitespaces only.
+   * @param {?string} str String to be tested.
+   * @return {boolean} |true| if the string is null, empty, or whitespaces.
+   * @private
+   */
+  isEmptyOrWhitespace_: function(str) {
+    return str === null || (/^\s*$/).test(str);
+  },
+
+  /**
    * Updates |currentView_| if the dialog had just opened and there's
    * only one local route.
    *
diff --git a/chrome/browser/resources/media_router/media_router_data.js b/chrome/browser/resources/media_router/media_router_data.js
index aec528c..4568566 100644
--- a/chrome/browser/resources/media_router/media_router_data.js
+++ b/chrome/browser/resources/media_router/media_router_data.js
@@ -150,19 +150,23 @@
   /**
    * @param {string} id The ID of the media sink.
    * @param {string} name The name of the sink.
+   * @param {?string} description Optional description of the sink.
    * @param {media_router.SinkIconType} iconType the type of icon for the sink.
    * @param {media_router.SinkStatus} status The readiness state of the sink.
    * @param {!Array<number>} castModes Cast modes compatible with the sink.
    * @constructor
    * @struct
    */
-  var Sink = function(id, name, iconType, status, castModes) {
+  var Sink = function(id, name, description, iconType, status, castModes) {
     /** @type {string} */
     this.id = id;
 
     /** @type {string} */
     this.name = name;
 
+    /** @type {?string} */
+    this.description = description;
+
     /** @type {SinkIconType} */
     this.iconType = iconType;
 
diff --git a/chrome/browser/resources/pdf/elements/viewer-zoom-toolbar/viewer-zoom-button.css b/chrome/browser/resources/pdf/elements/viewer-zoom-toolbar/viewer-zoom-button.css
index c9bb1896..02454185 100644
--- a/chrome/browser/resources/pdf/elements/viewer-zoom-toolbar/viewer-zoom-button.css
+++ b/chrome/browser/resources/pdf/elements/viewer-zoom-toolbar/viewer-zoom-button.css
@@ -8,12 +8,14 @@
 }
 
 :host([closed]) #wrapper {
-  transform: translateX(100%);
+  /* 132px roughly flips the location of the button across the right edge of the
+   * page. */
+  transform: translateX(132px);
   transition-timing-function: cubic-bezier(0.4, 0, 1, 1);
 }
 
 :host-context([dir=rtl]):host([closed]) #wrapper {
-  transform: translateX(-100%);
+  transform: translateX(-132px);
 }
 
 paper-fab {
@@ -26,6 +28,5 @@
   @apply(--shadow-elevation-4dp);
   background-color: rgb(242, 242, 242);
   color: rgb(96, 96, 96);
-  margin: 0 48px;
   overflow: visible;
 }
diff --git a/chrome/browser/resources/pdf/elements/viewer-zoom-toolbar/viewer-zoom-toolbar.css b/chrome/browser/resources/pdf/elements/viewer-zoom-toolbar/viewer-zoom-toolbar.css
index 4756c8b..c7577ef 100644
--- a/chrome/browser/resources/pdf/elements/viewer-zoom-toolbar/viewer-zoom-toolbar.css
+++ b/chrome/browser/resources/pdf/elements/viewer-zoom-toolbar/viewer-zoom-toolbar.css
@@ -16,6 +16,16 @@
   right: auto;
 }
 
+#zoom-buttons {
+  position: relative;
+  right: 48px;
+}
+
+:host-context([dir=rtl]) #zoom-buttons {
+  left: 48px;
+  right: auto;
+}
+
 viewer-zoom-button {
   display: block;
 }
diff --git a/chrome/browser/resources/pdf/elements/viewer-zoom-toolbar/viewer-zoom-toolbar.html b/chrome/browser/resources/pdf/elements/viewer-zoom-toolbar/viewer-zoom-toolbar.html
index a2e3b372..b1ee0d99 100644
--- a/chrome/browser/resources/pdf/elements/viewer-zoom-toolbar/viewer-zoom-toolbar.html
+++ b/chrome/browser/resources/pdf/elements/viewer-zoom-toolbar/viewer-zoom-toolbar.html
@@ -7,15 +7,13 @@
   <template>
 
     <div id="zoom-buttons">
-      <div id="buttons">
-        <viewer-zoom-button id="fit-button" icons="fullscreen-exit fullscreen"
-            on-fabclick="fitToggle" delay="100">
-        </viewer-zoom-button>
-        <viewer-zoom-button id="zoom-in-button" icons="add"
-            on-fabclick="zoomIn" delay="50"></viewer-zoom-button>
-        <viewer-zoom-button id="zoom-out-button" icons="remove"
-            on-fabclick="zoomOut" delay="0"></viewer-zoom-button>
-      </div>
+      <viewer-zoom-button id="fit-button" icons="fullscreen-exit fullscreen"
+          on-fabclick="fitToggle" delay="100">
+      </viewer-zoom-button>
+      <viewer-zoom-button id="zoom-in-button" icons="add"
+          on-fabclick="zoomIn" delay="50"></viewer-zoom-button>
+      <viewer-zoom-button id="zoom-out-button" icons="remove"
+          on-fabclick="zoomOut" delay="0"></viewer-zoom-button>
     </div>
   </template>
 </dom-module>
diff --git a/chrome/browser/resources/settings/a11y_page/a11y_page.html b/chrome/browser/resources/settings/a11y_page/a11y_page.html
index 66688cf..deeec10 100644
--- a/chrome/browser/resources/settings/a11y_page/a11y_page.html
+++ b/chrome/browser/resources/settings/a11y_page/a11y_page.html
@@ -3,7 +3,7 @@
 <link rel="import" href="chrome://md-settings/controls/settings_checkbox.html">
 
 <dom-module id="settings-a11y-page">
-  <link rel="import" type="css" href="chrome://md-settings/settings_page/settings_page.css">
+  <link rel="import" type="css" href="chrome://md-settings/settings_shared.css">
   <link rel="import" type="css" href="a11y_page.css">
   <template>
     <div class="settings-box">
diff --git a/chrome/browser/resources/settings/appearance_page/appearance_fonts_page.html b/chrome/browser/resources/settings/appearance_page/appearance_fonts_page.html
index d3f09a6..4d8d6045 100644
--- a/chrome/browser/resources/settings/appearance_page/appearance_fonts_page.html
+++ b/chrome/browser/resources/settings/appearance_page/appearance_fonts_page.html
@@ -4,7 +4,7 @@
 
 <dom-module id="settings-appearance-fonts-page">
   <link rel="import" type="css"
-      href="chrome://md-settings/settings_page/settings_page.css">
+      href="chrome://md-settings/settings_shared.css">
   <link rel="import" type="css"
       href="chrome://md-settings/appearance_page/appearance_shared.css">
   <template>
diff --git a/chrome/browser/resources/settings/appearance_page/appearance_page.html b/chrome/browser/resources/settings/appearance_page/appearance_page.html
index 75effa7..04a5f5a 100644
--- a/chrome/browser/resources/settings/appearance_page/appearance_page.html
+++ b/chrome/browser/resources/settings/appearance_page/appearance_page.html
@@ -15,7 +15,7 @@
 
 <dom-module id="settings-appearance-page">
   <link rel="import" type="css"
-      href="chrome://md-settings/settings_page/settings_page.css">
+      href="chrome://md-settings/settings_shared.css">
   <link rel="import" type="css"
       href="chrome://md-settings/appearance_page/appearance_shared.css">
   <link rel="import" type="css" href="chrome://resources/css/widgets.css">
diff --git a/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.html b/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.html
index 966ba25..0a5a725 100644
--- a/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.html
+++ b/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.html
@@ -11,7 +11,7 @@
 <link rel="import" href="chrome://md-settings/settings_page/settings_animated_pages.html">
 
 <dom-module id="settings-bluetooth-page">
-  <link rel="import" type="css" href="chrome://md-settings/settings_page/settings_page.css">
+  <link rel="import" type="css" href="chrome://md-settings/settings_shared.css">
   <link rel="import" type="css" href="bluetooth_page.css">
   <template>
     <settings-animated-pages id="pages" current-route="{{currentRoute}}"
diff --git a/chrome/browser/resources/settings/clear_browsing_data_page/clear_browsing_data_page.html b/chrome/browser/resources/settings/clear_browsing_data_page/clear_browsing_data_page.html
index 3ecec290..3edd6ddd 100644
--- a/chrome/browser/resources/settings/clear_browsing_data_page/clear_browsing_data_page.html
+++ b/chrome/browser/resources/settings/clear_browsing_data_page/clear_browsing_data_page.html
@@ -8,7 +8,7 @@
 
 <dom-module id="settings-clear-browsing-data-page">
   <link rel="import" type="css"
-      href="chrome://md-settings/settings_page/settings_page.css">
+      href="chrome://md-settings/settings_shared.css">
   <link rel="import" type="css" href="clear_browsing_data_page.css">
   <template>
     <div class="settings-box">
diff --git a/chrome/browser/resources/settings/controls/settings_dropdown_menu.html b/chrome/browser/resources/settings/controls/settings_dropdown_menu.html
index 4e771932..a7b2caa 100644
--- a/chrome/browser/resources/settings/controls/settings_dropdown_menu.html
+++ b/chrome/browser/resources/settings/controls/settings_dropdown_menu.html
@@ -7,7 +7,7 @@
 
 <dom-module id="settings-dropdown-menu">
   <link rel="import" type="css"
-      href="chrome://md-settings/settings_page/settings_page.css">
+      href="chrome://md-settings/settings_shared.css">
   <template>
     <paper-dropdown-menu id="dropdownMenu" label="[[menuLabel_]]"
         on-iron-select="onSelect_"
diff --git a/chrome/browser/resources/settings/date_time_page/date_time_page.html b/chrome/browser/resources/settings/date_time_page/date_time_page.html
index 6363c3f32..0a298433 100644
--- a/chrome/browser/resources/settings/date_time_page/date_time_page.html
+++ b/chrome/browser/resources/settings/date_time_page/date_time_page.html
@@ -4,7 +4,7 @@
 
 <dom-module id="settings-date-time-page">
   <link rel="import" type="css"
-      href="chrome://md-settings/settings_page/settings_page.css">
+      href="chrome://md-settings/settings_shared.css">
   <link rel="import" type="css" href="date_time_page.css">
   <template>
     <div class="horizontal layout center">
diff --git a/chrome/browser/resources/settings/default_browser_page/default_browser_page.html b/chrome/browser/resources/settings/default_browser_page/default_browser_page.html
index ae5c6857..fc63516 100644
--- a/chrome/browser/resources/settings/default_browser_page/default_browser_page.html
+++ b/chrome/browser/resources/settings/default_browser_page/default_browser_page.html
@@ -5,7 +5,7 @@
 
 <dom-module id="settings-default-browser-page">
   <link rel="import" type="css"
-      href="chrome://md-settings/settings_page/settings_page.css">
+      href="chrome://md-settings/settings_shared.css">
   <link rel="import" type="css" href="default_browser_page.css">
   <template>
     <div class="settings-box">[[message_]]</div>
diff --git a/chrome/browser/resources/settings/downloads_page/downloads_page.html b/chrome/browser/resources/settings/downloads_page/downloads_page.html
index bb3fb94..0f81e676 100644
--- a/chrome/browser/resources/settings/downloads_page/downloads_page.html
+++ b/chrome/browser/resources/settings/downloads_page/downloads_page.html
@@ -6,7 +6,7 @@
 
 <dom-module id="settings-downloads-page">
   <link rel="import" type="css"
-      href="chrome://md-settings/settings_page/settings_page.css">
+      href="chrome://md-settings/settings_shared.css">
   <link rel="import" type="css" href="downloads_page.css">
   <template>
     <div class="settings-box split">
diff --git a/chrome/browser/resources/settings/internet_page/internet_detail_page.html b/chrome/browser/resources/settings/internet_page/internet_detail_page.html
index 9e11b21..46eaa61 100644
--- a/chrome/browser/resources/settings/internet_page/internet_detail_page.html
+++ b/chrome/browser/resources/settings/internet_page/internet_detail_page.html
@@ -18,7 +18,7 @@
 <link rel="import" href="network_siminfo.html">
 
 <dom-module id="settings-internet-detail-page">
-  <link rel="import" type="css" href="chrome://md-settings/settings_page/settings_page.css">
+  <link rel="import" type="css" href="chrome://md-settings/settings_shared.css">
   <link rel="import" type="css" href="internet_detail_page.css">
   <template>
     <div class="layout vertical">
diff --git a/chrome/browser/resources/settings/internet_page/internet_known_networks_page.html b/chrome/browser/resources/settings/internet_page/internet_known_networks_page.html
index c6d1f50..6dd5f1e 100644
--- a/chrome/browser/resources/settings/internet_page/internet_known_networks_page.html
+++ b/chrome/browser/resources/settings/internet_page/internet_known_networks_page.html
@@ -5,7 +5,7 @@
 <link rel="import" href="chrome://resources/cr_elements/network/cr_network_list.html">
 
 <dom-module id="settings-internet-known-networks-page">
-  <link rel="import" type="css" href="chrome://md-settings/settings_page/settings_page.css">
+  <link rel="import" type="css" href="chrome://md-settings/settings_shared.css">
   <link rel="import" type="css" href="internet_known_networks_page.css">
   <template>
     <div class="layout vertical">
diff --git a/chrome/browser/resources/settings/internet_page/internet_page.html b/chrome/browser/resources/settings/internet_page/internet_page.html
index 995abea..543de58 100644
--- a/chrome/browser/resources/settings/internet_page/internet_page.html
+++ b/chrome/browser/resources/settings/internet_page/internet_page.html
@@ -9,7 +9,7 @@
 
 <dom-module id="settings-internet-page">
   <link rel="import" type="css"
-      href="chrome://md-settings/settings_page/settings_page.css">
+      href="chrome://md-settings/settings_shared.css">
   <template>
     <settings-animated-pages id="pages" current-route="{{currentRoute}}"
         section="internet">
diff --git a/chrome/browser/resources/settings/languages_page/compiled_resources.gyp b/chrome/browser/resources/settings/languages_page/compiled_resources.gyp
index 3726ded..67b25d33 100644
--- a/chrome/browser/resources/settings/languages_page/compiled_resources.gyp
+++ b/chrome/browser/resources/settings/languages_page/compiled_resources.gyp
@@ -11,6 +11,7 @@
           '../prefs/compiled_resources.gyp:prefs',
           '../../../../../ui/webui/resources/js/compiled_resources.gyp:assert',
           '../../../../../ui/webui/resources/js/compiled_resources.gyp:cr',
+          'languages_types.js',
         ],
         'externs': [
           '<(EXTERNS_DIR)/chrome_send.js',
@@ -27,6 +28,7 @@
           '../../../../../ui/webui/resources/js/chromeos/compiled_resources.gyp:ui_account_tweaks',
           '../../../../../ui/webui/resources/js/compiled_resources.gyp:load_time_data',
           '../prefs/compiled_resources.gyp:prefs',
+          'languages_types.js',
           'languages.js',
         ],
         'externs': [
@@ -45,6 +47,7 @@
           '../settings_page/settings_animated_pages.js',
           '../prefs/prefs_types.js',
           '../prefs/compiled_resources.gyp:prefs',
+          'languages_types.js',
           'languages.js',
         ],
         'externs': [
@@ -59,10 +62,11 @@
         'depends': [
           '../../../../../ui/webui/resources/js/compiled_resources.gyp:assert',
           '../prefs/compiled_resources.gyp:prefs',
+          'languages_types.js',
           'languages.js',
         ],
         'externs': [
-          '../../../../../third_party/closure_compiler/externs/language_settings_private.js',
+          '<(EXTERNS_DIR)/language_settings_private.js',
         ],
       },
       'includes': ['../../../../../third_party/closure_compiler/compile_js.gypi'],
diff --git a/chrome/browser/resources/settings/languages_page/edit_dictionary_page.html b/chrome/browser/resources/settings/languages_page/edit_dictionary_page.html
index 3d1dc31..6788df9 100644
--- a/chrome/browser/resources/settings/languages_page/edit_dictionary_page.html
+++ b/chrome/browser/resources/settings/languages_page/edit_dictionary_page.html
@@ -8,7 +8,7 @@
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-item/paper-item.html">
 
 <dom-module id="settings-edit-dictionary-page">
-  <link rel="import" type="css" href="chrome://md-settings/settings_page/settings_page.css">
+  <link rel="import" type="css" href="chrome://md-settings/settings_shared.css">
   <link rel="import" type="css" href="edit_dictionary_page.css">
   <template>
     <div class="settings-box">
diff --git a/chrome/browser/resources/settings/languages_page/language_detail_page.html b/chrome/browser/resources/settings/languages_page/language_detail_page.html
index 1de5209..28bc6d6 100644
--- a/chrome/browser/resources/settings/languages_page/language_detail_page.html
+++ b/chrome/browser/resources/settings/languages_page/language_detail_page.html
@@ -11,11 +11,10 @@
 </if>
 
 <dom-module id="settings-language-detail-page">
-  <link rel="import" type="css" href="chrome://md-settings/settings_page/settings_page.css">
+  <link rel="import" type="css" href="chrome://md-settings/settings_shared.css">
   <link rel="import" type="css" href="language_detail_page.css">
   <template>
-    <settings-languages id="languages" languages="{{languages}}">
-    </settings-languages>
+    <settings-languages languages="{{languages}}"></settings-languages>
 <if expr="chromeos or is_win">
     <div id="languageSettings">
       <label hidden$="[[!detail.language.supportsUI]]">
diff --git a/chrome/browser/resources/settings/languages_page/language_detail_page.js b/chrome/browser/resources/settings/languages_page/language_detail_page.js
index b3b9166..8f89226 100644
--- a/chrome/browser/resources/settings/languages_page/language_detail_page.js
+++ b/chrome/browser/resources/settings/languages_page/language_detail_page.js
@@ -35,6 +35,9 @@
     detail: Object,
   },
 
+  /** @private {!LanguageHelper} */
+  languageHelper_: LanguageHelperImpl.getInstance(),
+
   ready: function() {
     // In a CrOS multi-user session, the primary user controls the UI language.
     if (this.isSecondaryUser_()) {
@@ -51,15 +54,19 @@
     }
   },
 
+<if expr="chromeos or is_win">
   /**
+   * Checks whether the prospective UI language (the pref that indicates what
+   * language to use in Chrome) matches the current language. This pref is only
+   * on Chrome OS and Windows; we don't control the UI language elsewhere.
    * @param {string} languageCode The language code identifying a language.
-   * @param {string} prospectiveUILanguage The chosen UI language.
-   * @return {boolean} True if the given language matches the chosen UI language
-   *     (which may be different from the actual UI language).
+   * @param {string} prospectiveUILanguage The prospective UI language.
+   * @return {boolean} True if the given language matches the prospective UI
+   *     pref (which may be different from the actual UI language).
    * @private
    */
   isProspectiveUILanguage_: function(languageCode, prospectiveUILanguage) {
-    return languageCode == this.$.languages.getProspectiveUILanguage();
+    return languageCode == this.languageHelper_.getProspectiveUILanguage();
   },
 
   /**
@@ -73,6 +80,7 @@
     return languageCode == prospectiveUILanguage &&
            languageCode == navigator.language;
   },
+</if>
 
    /**
    * @param {string} languageCode The language code identifying a language.
@@ -81,7 +89,7 @@
    * @private
    */
   isTranslateDisabled_: function(languageCode, targetLanguageCode) {
-    return this.$.languages.convertLanguageCodeForTranslate(languageCode) ==
+    return this.languageHelper_.convertLanguageCodeForTranslate(languageCode) ==
         targetLanguageCode;
   },
 
@@ -140,9 +148,9 @@
    */
   onTranslateEnabledChange_: function(e) {
     if (e.target.checked)
-      this.$.languages.enableTranslateLanguage(this.detail.language.code);
+      this.languageHelper_.enableTranslateLanguage(this.detail.language.code);
     else
-      this.$.languages.disableTranslateLanguage(this.detail.language.code);
+      this.languageHelper_.disableTranslateLanguage(this.detail.language.code);
   },
 
   /**
@@ -152,10 +160,10 @@
    */
   onUILanguageChange_: function(e) {
     if (e.target.checked) {
-      this.$.languages.setUILanguage(this.detail.language.code);
+      this.languageHelper_.setUILanguage(this.detail.language.code);
     } else {
       // Reset the chosen UI language to the actual UI language.
-      this.$.languages.resetUILanguage();
+      this.languageHelper_.resetUILanguage();
     }
   },
 
diff --git a/chrome/browser/resources/settings/languages_page/languages.js b/chrome/browser/resources/settings/languages_page/languages.js
index bedacd7..a892542 100644
--- a/chrome/browser/resources/settings/languages_page/languages.js
+++ b/chrome/browser/resources/settings/languages_page/languages.js
@@ -9,9 +9,9 @@
  * Instances of this element have a 'languages' property, which reflects the
  * current language settings. The 'languages' property is read-only, meaning
  * hosts using this element cannot change it directly. Instead, changes to
- * language settings should be made using this element's public functions.
+ * language settings should be made using the LanguageHelperImpl singleton.
  *
- * Use two-way binding syntax to propagate changes from child to host, so that
+ * Use upward binding syntax to propagate changes from child to host, so that
  * changes made internally to 'languages' propagate to your host element:
  *
  *     <template>
@@ -24,26 +24,7 @@
  * @element settings-languages
  */
 
-/** @typedef {{spellCheckEnabled: boolean, translateEnabled: boolean}} */
-var LanguageState;
-
-/**
- * @typedef {{language: !chrome.languageSettingsPrivate.Language,
- *            state: !LanguageState}}
- */
-var LanguageInfo;
-
-/**
- * supportedLanguages: an array of languages, ordered alphabetically.
- * enabledLanguages: an array of enabled language info and state, ordered by
- *     preference.
- * @typedef {{
- *      supportedLanguages: !Array<!chrome.languageSettingsPrivate.Language>,
- *      enabledLanguages: !Array<!LanguageInfo>,
- *      translateTarget: string
- *  }}
- */
-var LanguagesModel;
+var SettingsLanguagesSingletonElement;
 
 (function() {
 'use strict';
@@ -66,130 +47,17 @@
   'jv': 'jw',
 };
 
-/**
- * This element has a reference to the singleton, exposing the singleton's
- * language model to the host of this element as the 'languages' property.
- */
-Polymer({
-  is: 'settings-languages',
-
-  properties: {
-    /**
-     * Singleton element created at startup which provides the languages model.
-     * @type {!Element}
-     */
-    singleton_: {
-      type: Object,
-      value: document.createElement('settings-languages-singleton'),
-    },
-
-    /**
-     * A reference to the languages model from the singleton, exposed as a
-     * read-only property so hosts can bind to it, but not change it.
-     * @type {LanguagesModel|undefined}
-     */
-    languages: {
-      type: Object,
-      notify: true,
-      readOnly: true,
-    },
-  },
-
-  ready: function() {
-    // Set the 'languages' property to reference the singleton's model.
-    this._setLanguages(this.singleton_.languages);
-    // Listen for changes to the singleton's languages property, so we know
-    // when to notify hosts of changes to (our reference to) the property.
-    this.listen(
-        this.singleton_, 'languages-changed', 'singletonLanguagesChanged_');
-  },
-
-  /**
-   * Takes changes reported by the singleton and forwards them to the host,
-   * manually sending a change notification for our 'languages' property (since
-   * it's the same object as the singleton's property, but isn't bound by
-   * Polymer).
-   * @private
-   */
-  singletonLanguagesChanged_: function(e) {
-    // Forward the change notification to the host.
-    this.fire(e.type, e.detail, {bubbles: false});
-  },
-
-  // Forward public methods to the singleton.
-
-  /** @param {string} languageCode */
-  setUILanguage: function(languageCode) {
-    if (cr.isWindows || cr.isChromeOS)
-      this.singleton_.setUILanguage(languageCode);
-  },
-
-  resetUILanguage: function() {
-    if (cr.isWindows || cr.isChromeOS)
-      this.singleton_.resetUILanguage();
-  },
-
-  /** @return {string} */
-  getProspectiveUILanguage: function() {
-    return this.singleton_.getProspectiveUILanguage();
-  },
-
-  /** @param {string} languageCode */
-  enableLanguage: function(languageCode) {
-    this.singleton_.enableLanguage(languageCode);
-  },
-
-  /** @param {string} languageCode */
-  disableLanguage: function(languageCode) {
-    this.singleton_.disableLanguage(languageCode);
-  },
-
-  /** @param {string} languageCode */
-  enableTranslateLanguage: function(languageCode) {
-    this.singleton_.enableTranslateLanguage(languageCode);
-  },
-
-  /** @param {string} languageCode */
-  disableTranslateLanguage: function(languageCode) {
-    this.singleton_.disableTranslateLanguage(languageCode);
-  },
-
-  /**
-   * @param {string} languageCode
-   * @return {boolean}
-   */
-  isEnabled: function(languageCode) {
-    return this.singleton_.isEnabled(languageCode);
-  },
-
-  /**
-   * @param {string} languageCode
-   * @param {boolean} enable
-   */
-  toggleSpellCheck: function(languageCode, enable) {
-    this.singleton_.toggleSpellCheck(languageCode, enable);
-  },
-
-  /**
-   * @param {string} languageCode
-   * @return {string}
-   */
-  convertLanguageCodeForTranslate: function(languageCode) {
-    return this.singleton_.convertLanguageCodeForTranslate(languageCode);
-  },
-});
-
 var preferredLanguagesPrefName = cr.isChromeOS ?
     'settings.language.preferred_languages' : 'intl.accept_languages';
 
 /**
- * Singleton element created when settings-languages is registered.
- * Generates the languages model on start-up, and updates it whenever Chrome's
- * pref store and other settings change. These updates propagate to each
- * <settings-language> instance so that their 'languages' property updates
- * like any other Polymer property.
+ * Singleton element that generates the languages model on start-up and
+ * updates it whenever Chrome's pref store and other settings change. These
+ * updates propagate to each <settings-language> instance so that their
+ * 'languages' property updates like any other Polymer property.
+ * @implements {LanguageHelper}
  */
-Polymer({
+SettingsLanguagesSingletonElement = Polymer({
   is: 'settings-languages-singleton',
 
   behaviors: [PrefsBehavior],
@@ -267,11 +135,68 @@
   },
 
   /**
+   * Updates the list of enabled languages from the preferred languages pref.
+   * @private
+   */
+  preferredLanguagesPrefChanged_: function() {
+    if (!this.initialized_)
+      return;
+
+    var enabledLanguages =
+        this.getEnabledLanguages_(this.languages.translateTarget);
+
+    // Reset the enabled language map before updating
+    // languages.enabledLanguages.
+    this.enabledLanguageMap_ = {};
+    for (var i = 0; i < enabledLanguages.length; i++) {
+      var languageInfo = enabledLanguages[i];
+      this.enabledLanguageMap_[languageInfo.language.code] = languageInfo;
+    }
+    this.set('languages.enabledLanguages', enabledLanguages);
+  },
+
+  /**
+   * Updates the spellCheckEnabled state of each enabled language.
+   * @private
+   */
+  spellCheckDictionariesPrefChanged_: function() {
+    if (!this.initialized_)
+      return;
+
+    var spellCheckMap = this.makeMapFromArray_(/** @type {!Array<string>} */(
+        this.getPref('spellcheck.dictionaries').value));
+    for (var i = 0; i < this.languages.enabledLanguages.length; i++) {
+      var languageCode = this.languages.enabledLanguages[i].language.code;
+      this.set('languages.enabledLanguages.' + i + '.state.spellCheckEnabled',
+               !!spellCheckMap[languageCode]);
+    }
+  },
+
+  /** @private */
+  translateLanguagesPrefChanged_: function() {
+    if (!this.initialized_)
+      return;
+
+    var translateBlockedPref = this.getPref('translate_blocked_languages');
+    var translateBlockedMap = this.makeMapFromArray_(
+        /** @type {!Array<string>} */(translateBlockedPref.value));
+
+    for (var i = 0; i < this.languages.enabledLanguages.length; i++) {
+      var translateCode = this.convertLanguageCodeForTranslate(
+          this.languages.enabledLanguages[i].language.code);
+      this.set(
+          'languages.enabledLanguages.' + i + '.state.translateEnabled',
+          !translateBlockedMap[translateCode]);
+    }
+  },
+
+  /**
    * Constructs the languages model.
    * @param {!Array<!chrome.languageSettingsPrivate.Language>}
    *     supportedLanguages
    * @param {string} translateTarget Language code of the default translate
    *     target language.
+   * @private
    */
   createModel_: function(supportedLanguages, translateTarget) {
     // Populate the hash map of supported languages.
@@ -325,17 +250,19 @@
     for (var i = 0; i < enabledLanguageCodes.length; i++) {
       var code = enabledLanguageCodes[i];
       var language = this.supportedLanguageMap_[code];
+      // Skip unsupported languages.
       if (!language)
         continue;
-      var state = {};
+      var state = /** @type {LanguageState} */({});
       state.spellCheckEnabled = !!spellCheckMap[code];
       // Translate is considered disabled if this language maps to any translate
       // language that is blocked.
       var translateCode = this.convertLanguageCodeForTranslate(code);
-      state.translateEnabled = language.supportsTranslate &&
+      state.translateEnabled = !!language.supportsTranslate &&
           !translateBlockedMap[translateCode] &&
           translateCode != translateTarget;
-      enabledLanguages.push({language: language, state: state});
+      enabledLanguages.push(/** @type {LanguageInfo} */(
+          {language: language, state: state}));
     }
     return enabledLanguages;
   },
@@ -344,6 +271,7 @@
    * Creates an object whose keys are the elements of the list.
    * @param {!Array<string>} list
    * @return {!Object<boolean>}
+   * @private
    */
   makeMapFromArray_: function(list) {
     var map = {};
@@ -352,84 +280,21 @@
     return map;
   },
 
+  // LanguageHelper implementation.
+  // TODO(michaelpg): replace duplicate docs with @override once b/24294625
+  // is fixed.
+
+<if expr="chromeos or is_win">
   /**
-   * Updates the list of enabled languages from the preferred languages pref.
-   * @private
-   * */
-  preferredLanguagesPrefChanged_: function() {
-    if (!this.initialized_)
-      return;
-
-    var enabledLanguages =
-        this.getEnabledLanguages_(this.languages.translateTarget);
-    // Reset the enabled language map. Do this before notifying of the change
-    // via languages.enabledLanguages.
-    this.enabledLanguageMap_ = {};
-    for (var i = 0; i < enabledLanguages.length; i++) {
-      var languageInfo = enabledLanguages[i];
-      this.enabledLanguageMap_[languageInfo.language.code] = languageInfo;
-    }
-    this.set('languages.enabledLanguages', enabledLanguages);
-  },
-
-  /**
-   * Updates the spellCheckEnabled state of each enabled language.
-   * @private
-   */
-  spellCheckDictionariesPrefChanged_: function() {
-    if (!this.initialized_)
-      return;
-
-    var spellCheckMap = this.makeMapFromArray_(/** @type {!Array<string>} */(
-        this.getPref('spellcheck.dictionaries').value));
-    for (var i = 0; i < this.languages.enabledLanguages.length; i++) {
-      var languageCode = this.languages.enabledLanguages[i].language.code;
-      this.set('languages.enabledLanguages.' + i + '.state.spellCheckEnabled',
-               !!spellCheckMap[languageCode]);
-    }
-  },
-
-  translateLanguagesPrefChanged_: function() {
-    if (!this.initialized_)
-      return;
-
-    var translateBlockedPref = this.getPref('translate_blocked_languages');
-    var translateBlockedMap = this.makeMapFromArray_(
-        /** @type {!Array<string>} */(translateBlockedPref.value));
-
-    for (var i = 0; i < this.languages.enabledLanguages.length; i++) {
-      var translateCode = this.convertLanguageCodeForTranslate(
-          this.languages.enabledLanguages[i].language.code);
-      this.set(
-          'languages.enabledLanguages.' + i + '.state.translateEnabled',
-          !translateBlockedMap[translateCode]);
-    }
-  },
-
-  /**
-   * Deletes the given item from the pref at the given key if the item is found.
-   * Asserts if the pref itself is not found or is not an Array type.
-   * @param {string} key
-   * @param {*} item
-   */
-  deletePrefItem_: function(key, item) {
-    assert(this.getPref(key).type == chrome.settingsPrivate.PrefType.LIST);
-    this.arrayDelete('prefs.' + key + '.value', item);
-  },
-
-  /**
-   * Windows and Chrome OS only: Sets the prospective UI language to the chosen
-   * language. This dosen't affect the actual UI language until a restart.
+   * Sets the prospective UI language to the chosen language. This won't affect
+   * the actual UI language until a restart.
    * @param {string} languageCode
    */
   setUILanguage: function(languageCode) {
     chrome.send('setUILanguage', [languageCode]);
   },
 
-  /**
-   * Windows and Chrome OS only: Resets the prospective UI language back to the
-   * actual UI language.
-   */
+  /** Resets the prospective UI language back to the actual UI language. */
   resetUILanguage: function() {
     chrome.send('setUILanguage', [navigator.language]);
   },
@@ -439,12 +304,20 @@
    * restart. If the pref is not set, the current UI language is also the
    * "prospective" language.
    * @return {string} Language code of the prospective UI language.
-   * @private
    */
   getProspectiveUILanguage: function() {
     return /** @type {string} */(this.getPref('intl.app_locale').value) ||
         navigator.language;
   },
+</if>
+
+  /**
+   * @param {string} languageCode
+   * @return {boolean} True if the language is enabled.
+   */
+  isLanguageEnabled: function(languageCode) {
+    return !!this.enabledLanguageMap_[languageCode];
+  },
 
   /**
    * Enables the language, making it available for spell check and input.
@@ -471,17 +344,14 @@
     if (!CrSettingsPrefs.isInitialized)
       return;
 
-    // Cannot disable the UI language.
-    assert(languageCode != this.getProspectiveUILanguage());
-
-    // Cannot disable the only enabled language.
-    var languageCodes =
-        this.getPref(preferredLanguagesPrefName).value.split(',');
-    assert(languageCodes.length > 1);
+    assert(this.canDisableLanguage(languageCode));
 
     // Remove the language from spell check.
-    this.deletePrefItem_('spellcheck.dictionaries', languageCode);
+    this.deletePrefListItem('spellcheck.dictionaries', languageCode);
 
+    // Remove the language from preferred languages.
+    var languageCodes =
+        this.getPref(preferredLanguagesPrefName).value.split(',');
     var languageIndex = languageCodes.indexOf(languageCode);
     if (languageIndex == -1)
       return;
@@ -491,11 +361,21 @@
   },
 
   /**
-   * @param {string} languageCode
-   * @return {boolean} True if the language is enabled.
+   * @param {string} languageCode Language code for an enabled language.
+   * @return {boolean}
    */
-  isEnabled: function(languageCode) {
-    return !!this.enabledLanguageMap_[languageCode];
+  canDisableLanguage: function(languageCode) {
+    // Cannot disable the prospective UI language.
+    if ((cr.isChromeOS || cr.isWindows) &&
+        languageCode == this.getProspectiveUILanguage()) {
+      return false;
+    }
+
+    // Cannot disable the only enabled language.
+    if (this.languages.enabledLanguages.length == 1)
+      return false;
+
+    return true;
   },
 
   /**
@@ -505,7 +385,7 @@
    */
   enableTranslateLanguage: function(languageCode) {
     languageCode = this.convertLanguageCodeForTranslate(languageCode);
-    this.arrayDelete('prefs.translate_blocked_languages.value', languageCode);
+    this.deletePrefListItem('translate_blocked_languages', languageCode);
   },
 
   /**
@@ -514,11 +394,8 @@
    * @param {string} languageCode
    */
   disableTranslateLanguage: function(languageCode) {
-    languageCode = this.convertLanguageCodeForTranslate(languageCode);
-    if (this.getPref('translate_blocked_languages').value
-            .indexOf(languageCode) == -1) {
-      this.push('prefs.translate_blocked_languages.value', languageCode);
-    }
+    this.appendPrefListItem('translate_blocked_languages',
+        this.convertLanguageCodeForTranslate(languageCode));
   },
 
   /**
@@ -532,10 +409,9 @@
 
     if (enable) {
       var spellCheckPref = this.getPref('spellcheck.dictionaries');
-      if (spellCheckPref.value.indexOf(languageCode) == -1)
-        this.push('prefs.spellcheck.dictionaries.value', languageCode);
+      this.appendPrefListItem('spellcheck.dictionaries', languageCode);
     } else {
-      this.arrayDelete('prefs.spellcheck.dictionaries.value', languageCode);
+      this.deletePrefListItem('spellcheck.dictionaries', languageCode);
     }
   },
 
@@ -545,7 +421,6 @@
    * Accept-Language.
    * @param {string} languageCode
    * @return {string} The converted language code.
-   * @private
    */
   convertLanguageCodeForTranslate: function(languageCode) {
     if (languageCode in kLanguageCodeToTranslateCode)
@@ -562,5 +437,72 @@
 
     return main;
   },
+
+  /**
+   * @param {string} languageCode
+   * @return {!chrome.languageSettingsPrivate.Language|undefined}
+   */
+  getLanguage: function(languageCode) {
+    return this.supportedLanguageMap_[languageCode];
+  },
 });
 })();
+
+/**
+ * A reference to the singleton under the guise of a LanguageHelper
+ * implementation. This provides a limited API but implies the singleton
+ * should not be used directly for data binding.
+ */
+var LanguageHelperImpl = SettingsLanguagesSingletonElement;
+cr.addSingletonGetter(LanguageHelperImpl);
+
+/**
+ * This element has a reference to the singleton, exposing the singleton's
+ * |languages| model to the host of this element.
+ */
+Polymer({
+  is: 'settings-languages',
+
+  properties: {
+    /**
+     * Singleton element created at startup which provides the languages model.
+     * @type {!SettingsLanguagesSingletonElement}
+     */
+    singleton_: {
+      type: Object,
+      value: LanguageHelperImpl.getInstance(),
+    },
+
+    /**
+     * A reference to the languages model from the singleton, exposed as a
+     * read-only property so hosts can bind to it, but not change it.
+     * @type {LanguagesModel|undefined}
+     */
+    languages: {
+      type: Object,
+      notify: true,
+      readOnly: true,
+    },
+  },
+
+  ready: function() {
+    // Set the 'languages' property to reference the singleton's model.
+    this._setLanguages(this.singleton_.languages);
+    // Listen for changes to the singleton's languages property, so we know
+    // when to notify hosts of changes to (our reference to) the property.
+    this.listen(
+        this.singleton_, 'languages-changed', 'singletonLanguagesChanged_');
+  },
+
+  /**
+   * Takes changes reported by the singleton and forwards them to the host,
+   * manually sending a change notification for our 'languages' property (since
+   * it's the same object as the singleton's property, but isn't bound by
+   * Polymer).
+   * @private
+   */
+  singletonLanguagesChanged_: function(e) {
+    // Forward the change notification to the host.
+    this.fire(e.type, e.detail, {bubbles: false});
+  },
+});
diff --git a/chrome/browser/resources/settings/languages_page/languages_page.html b/chrome/browser/resources/settings/languages_page/languages_page.html
index 38fd7aa..882342c7 100644
--- a/chrome/browser/resources/settings/languages_page/languages_page.html
+++ b/chrome/browser/resources/settings/languages_page/languages_page.html
@@ -20,11 +20,10 @@
 
 <dom-module id="settings-languages-page">
   <link rel="import" type="css"
-      href="chrome://md-settings/settings_page/settings_page.css">
+      href="chrome://md-settings/settings_shared.css">
   <link rel="import" type="css" href="languages_page.css">
   <template>
-    <settings-languages id="languages" languages="{{languages}}">
-    </settings-languages>
+    <settings-languages languages="{{languages}}"></settings-languages>
     <settings-animated-pages id="pages" current-route="{{currentRoute}}"
         section="languages">
       <neon-animatable id="main">
@@ -37,9 +36,11 @@
               <paper-item class="split" on-tap="onLanguageTap_">
                 <div class="flex" title="[[item.language.nativeDisplayName]]"
                     >[[item.language.displayName]]</div>
+<if expr="chromeos or is_win">
                 <iron-icon icon="done"
-                    hidden$="[[!isUILanguage_(item.language.code, prefs.intl.app_locale.value)]]">
+                    hidden$="[[!isProspectiveUILanguage_(item.language.code, prefs.intl.app_locale.value)]]">
                 </iron-icon>
+</if>
                 <paper-icon-button icon="settings"
                     on-tap="onShowLanguageDetailTap_"></paper-icon-button>
               </paper-item>
diff --git a/chrome/browser/resources/settings/languages_page/languages_page.js b/chrome/browser/resources/settings/languages_page/languages_page.js
index dd43e36..12c83e3a 100644
--- a/chrome/browser/resources/settings/languages_page/languages_page.js
+++ b/chrome/browser/resources/settings/languages_page/languages_page.js
@@ -43,19 +43,26 @@
     },
   },
 
+  /** @private {!LanguageHelper} */
+  languageHelper_: LanguageHelperImpl.getInstance(),
+
   /**
    * Handler for clicking a language on the main page, which selects the
    * language as the prospective UI language on Chrome OS and Windows.
    * @param {!{model: !{item: !LanguageInfo}}} e
    */
   onLanguageTap_: function(e) {
+    // Only change the UI language on platforms that allow it.
+    if (!cr.isChromeOS && !cr.isWindows)
+      return;
+
     // Taps on the paper-icon-button are handled in onShowLanguageDetailTap_.
     if (e.target.tagName == 'PAPER-ICON-BUTTON')
       return;
 
     // Set the prospective UI language. This won't take effect until a restart.
     if (e.model.item.language.supportsUI)
-      this.$.languages.setUILanguage(e.model.item.language.code);
+      this.languageHelper_.setUILanguage(e.model.item.language.code);
   },
 
   /**
@@ -63,8 +70,8 @@
    * @param {!{target: Element, model: !{item: !LanguageInfo}}} e
    */
   onSpellCheckChange_: function(e) {
-    this.$.languages.toggleSpellCheck(e.model.item.language.code,
-                                      e.target.checked);
+    this.languageHelper_.toggleSpellCheck(e.model.item.language.code,
+                                          e.target.checked);
   },
 
   /** @private */
@@ -102,16 +109,21 @@
   },
 </if>
 
+<if expr="chromeos or is_win">
   /**
+   * Checks whether the prospective UI language (the pref that indicates what
+   * language to use in Chrome) matches the current language. This pref is only
+   * on Chrome OS and Windows; we don't control the UI language elsewhere.
    * @param {string} languageCode The language code identifying a language.
    * @param {string} prospectiveUILanguage The prospective UI language.
    * @return {boolean} True if the given language matches the prospective UI
    *     pref (which may be different from the actual UI language).
    * @private
    */
-  isUILanguage_: function(languageCode, prospectiveUILanguage) {
-    return languageCode == this.$.languages.getProspectiveUILanguage();
+  isProspectiveUILanguage_: function(languageCode, prospectiveUILanguage) {
+    return languageCode == this.languageHelper_.getProspectiveUILanguage();
   },
+</if>
 
   /**
    * @param {string} id The input method ID.
diff --git a/chrome/browser/resources/settings/languages_page/languages_types.js b/chrome/browser/resources/settings/languages_page/languages_types.js
new file mode 100644
index 0000000..895d3469b
--- /dev/null
+++ b/chrome/browser/resources/settings/languages_page/languages_types.js
@@ -0,0 +1,127 @@
+// 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.
+
+/**
+ * @fileoverview Closure typedefs for dictionaries and interfaces used by
+ * language settings.
+ */
+
+/**
+ * Current properties of a language.
+ * @typedef {{spellCheckEnabled: boolean, translateEnabled: boolean,
+ *            removable: boolean}} */
+var LanguageState;
+
+/**
+ * Information about a language including intrinsic information (|language|)
+ * and the |state| of the language.
+ * @typedef {{language: !chrome.languageSettingsPrivate.Language,
+ *            state: !LanguageState}}
+ */
+var LanguageInfo;
+
+/**
+ * Languages data to expose to consumers.
+ * supportedLanguages: an array of languages, ordered alphabetically.
+ * enabledLanguages: an array of enabled language info, ordered by preference.
+ * translateTarget: the default language to translate into.
+ * @typedef {{
+ *   supportedLanguages: !Array<!chrome.languageSettingsPrivate.Language>,
+ *   enabledLanguages: !Array<!LanguageInfo>,
+ *   translateTarget: string
+ * }}
+ */
+var LanguagesModel;
+
+/**
+ * Helper methods implemented by settings-languages-singleton. The nature of
+ * the interaction between the singleton Polymer element and the |languages|
+ * properties kept in sync is hidden from the consumer, which can just treat
+ * these methods as a handy interface.
+ * @interface
+ */
+var LanguageHelper = function() {};
+
+LanguageHelper.prototype = {
+
+<if expr="chromeos or is_win">
+  /**
+   * Sets the prospective UI language to the chosen language. This won't affect
+   * the actual UI language until a restart.
+   * @param {string} languageCode
+   */
+  setUILanguage: assertNotReached,
+
+  /** Resets the prospective UI language back to the actual UI language. */
+  resetUILanguage: assertNotReached,
+
+  /**
+   * Returns the "prospective" UI language, i.e. the one to be used on next
+   * restart. If the pref is not set, the current UI language is also the
+   * "prospective" language.
+   * @return {string} Language code of the prospective UI language.
+   */
+  getProspectiveUILanguage: assertNotReached,
+</if>
+
+  /**
+   * @param {string} languageCode
+   * @return {boolean}
+   */
+  isLanguageEnabled: assertNotReached,
+
+  /**
+   * Enables the language, making it available for spell check and input.
+   * @param {string} languageCode
+   */
+  enableLanguage: assertNotReached,
+
+  /**
+   * Disables the language.
+   * @param {string} languageCode
+   */
+  disableLanguage: assertNotReached,
+
+  /**
+   * @param {string} languageCode Language code for an enabled language.
+   * @return {boolean}
+   */
+  canDisableLanguage: assertNotReached,
+
+  /**
+   * Enables translate for the given language by removing the translate
+   * language from the blocked languages preference.
+   * @param {string} languageCode
+   */
+  enableTranslateLanguage: assertNotReached,
+
+  /**
+   * Disables translate for the given language by adding the translate
+   * language to the blocked languages preference.
+   * @param {string} languageCode
+   */
+  disableTranslateLanguage: assertNotReached,
+
+  /**
+   * Enables or disables spell check for the given language.
+   * @param {string} languageCode
+   * @param {boolean} enable
+   */
+  toggleSpellCheck: assertNotReached,
+
+  /**
+   * Converts the language code for translate. There are some differences
+   * between the language set the Translate server uses and that for
+   * Accept-Language.
+   * @param {string} languageCode
+   * @return {string} The converted language code.
+   */
+  convertLanguageCodeForTranslate: assertNotReached,
+
+  /**
+   * @param {string} languageCode
+   * @return {!chrome.languageSettingsPrivate.Language|undefined}
+   */
+  getLanguage: assertNotReached,
+};
diff --git a/chrome/browser/resources/settings/languages_page/manage_languages_page.html b/chrome/browser/resources/settings/languages_page/manage_languages_page.html
index 5051ce5..393585f5 100644
--- a/chrome/browser/resources/settings/languages_page/manage_languages_page.html
+++ b/chrome/browser/resources/settings/languages_page/manage_languages_page.html
@@ -11,11 +11,10 @@
 
 <dom-module id="settings-manage-languages-page">
   <link rel="import" type="css"
-      href="chrome://md-settings/settings_page/settings_page.css">
+      href="chrome://md-settings/settings_shared.css">
   <link rel="import" type="css" href="manage_languages_page.css">
   <template>
-    <settings-languages id="languages" languages="{{languages}}">
-    </settings-languages>
+    <settings-languages languages="{{languages}}"></settings-languages>
     <div class="settings-box content">
       <h2 i18n-content="enabledLanguages"></h2>
       <div>
diff --git a/chrome/browser/resources/settings/languages_page/manage_languages_page.js b/chrome/browser/resources/settings/languages_page/manage_languages_page.js
index 9dda84c1..36a8cc4 100644
--- a/chrome/browser/resources/settings/languages_page/manage_languages_page.js
+++ b/chrome/browser/resources/settings/languages_page/manage_languages_page.js
@@ -37,6 +37,9 @@
     availableLanguages_: Array,
   },
 
+  /** @private {!LanguageHelper} */
+  languageHelper_: LanguageHelperImpl.getInstance(),
+
   observers: [
     'enabledLanguagesChanged_(languages.enabledLanguages.*)',
   ],
@@ -47,7 +50,7 @@
    * @private
    */
   onRemoveLanguageTap_: function(e) {
-    this.$.languages.disableLanguage(e.model.item.language.code);
+    this.languageHelper_.disableLanguage(e.model.item.language.code);
   },
 
   /**
@@ -56,19 +59,19 @@
    * @private
    */
   onAddLanguageTap_: function(e) {
-    this.$.languages.enableLanguage(e.model.item.code);
+    this.languageHelper_.enableLanguage(e.model.item.code);
   },
 
   /**
    * True if a language is not the current or prospective UI language.
    * @param {string} languageCode
-   * @param {!Array<!LanguageInfo>} prospectiveUILanguage
+   * @param {string} prospectiveUILanguageCode
    * @return {boolean}
    * @private
    */
-  canRemoveLanguage_: function(languageCode, prospectiveUILanguage) {
+  canRemoveLanguage_: function(languageCode, prospectiveUILanguageCode) {
     if (languageCode == navigator.language ||
-        languageCode == prospectiveUILanguage) {
+        languageCode == prospectiveUILanguageCode) {
       return false;
     }
     assert(this.languages.enabledLanguages.length > 1);
@@ -88,7 +91,7 @@
           code: language.code,
           displayName: language.displayName,
           nativeDisplayName: language.nativeDisplayName,
-          enabled: this.$.languages.isEnabled(language.code)
+          enabled: this.languageHelper_.isLanguageEnabled(language.code),
         });
       }
       // Set the Polymer property after building the full array.
@@ -97,7 +100,8 @@
       // Update the available languages in place.
       for (var i = 0; i < this.availableLanguages_.length; i++) {
         this.set('availableLanguages_.' + i + '.enabled',
-                 this.$.languages.isEnabled(this.availableLanguages_[i].code));
+                 this.languageHelper_.isLanguageEnabled(
+                      this.availableLanguages_[i].code));
       }
     }
   },
diff --git a/chrome/browser/resources/settings/on_startup_page/on_startup_page.html b/chrome/browser/resources/settings/on_startup_page/on_startup_page.html
index 1d823303..53d082c 100644
--- a/chrome/browser/resources/settings/on_startup_page/on_startup_page.html
+++ b/chrome/browser/resources/settings/on_startup_page/on_startup_page.html
@@ -9,7 +9,7 @@
 
 <dom-module id="settings-on-startup-page">
   <link rel="import" type="css"
-      href="chrome://md-settings/settings_page/settings_page.css">
+      href="chrome://md-settings/settings_shared.css">
   <link rel="import" type="css" href="on_startup_shared.css">
   <template>
     <settings-animated-pages id="pages" current-route="{{currentRoute}}"
diff --git a/chrome/browser/resources/settings/on_startup_page/startup_urls_page.html b/chrome/browser/resources/settings/on_startup_page/startup_urls_page.html
index a4e3a771..f68e8da 100644
--- a/chrome/browser/resources/settings/on_startup_page/startup_urls_page.html
+++ b/chrome/browser/resources/settings/on_startup_page/startup_urls_page.html
@@ -3,7 +3,7 @@
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-item/paper-icon-item.html">
 
 <dom-module id="settings-startup-urls-page">
-  <link rel="import" type="css" href="chrome://md-settings/settings_page/settings_page.css">
+  <link rel="import" type="css" href="chrome://md-settings/settings_shared.css">
   <link rel="import" type="css" href="on_startup_shared.css">
   <template>
     <div class="settings-box">
diff --git a/chrome/browser/resources/settings/passwords_and_forms_page/passwords_and_forms_page.html b/chrome/browser/resources/settings/passwords_and_forms_page/passwords_and_forms_page.html
index 6041ca6..8a733ff 100644
--- a/chrome/browser/resources/settings/passwords_and_forms_page/passwords_and_forms_page.html
+++ b/chrome/browser/resources/settings/passwords_and_forms_page/passwords_and_forms_page.html
@@ -6,7 +6,7 @@
 
 <dom-module id="settings-passwords-and-forms-page">
   <link rel="import" type="css"
-      href="chrome://md-settings/settings_page/settings_page.css">
+      href="chrome://md-settings/settings_shared.css">
   <template>
     <div class="settings-box">
       <paper-item>
diff --git a/chrome/browser/resources/settings/prefs/prefs_behavior.js b/chrome/browser/resources/settings/prefs/prefs_behavior.js
index 5a4c15d..8c94460 100644
--- a/chrome/browser/resources/settings/prefs/prefs_behavior.js
+++ b/chrome/browser/resources/settings/prefs/prefs_behavior.js
@@ -32,4 +32,31 @@
     this.getPref(prefPath);  // Ensures we throw if the pref is not found.
     this.set('prefs.' + prefPath + '.value', value);
   },
+
+  /**
+   * Appends the item to the pref list at the given key if the item is not
+   * already in the list. Asserts if the pref itself is not found or is not an
+   * Array type.
+   * @param {string} key
+   * @param {*} item
+   * @protected
+   */
+  appendPrefListItem: function(key, item) {
+    var pref = this.getPref(key);
+    assert(pref && pref.type == chrome.settingsPrivate.PrefType.LIST);
+    if (pref.value.indexOf(item) == -1)
+      this.push('prefs.' + key + '.value', item);
+  },
+
+  /**
+   * Deletes the given item from the pref at the given key if the item is found.
+   * Asserts if the pref itself is not found or is not an Array type.
+   * @param {string} key
+   * @param {*} item
+   * @protected
+   */
+  deletePrefListItem: function(key, item) {
+    assert(this.getPref(key).type == chrome.settingsPrivate.PrefType.LIST);
+    this.arrayDelete('prefs.' + key + '.value', item);
+  },
 };
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_page.html b/chrome/browser/resources/settings/privacy_page/privacy_page.html
index 410da507..008ede1 100644
--- a/chrome/browser/resources/settings/privacy_page/privacy_page.html
+++ b/chrome/browser/resources/settings/privacy_page/privacy_page.html
@@ -13,7 +13,7 @@
 
 <dom-module id="settings-privacy-page">
   <link rel="import" type="css"
-      href="chrome://md-settings/settings_page/settings_page.css">
+      href="chrome://md-settings/settings_shared.css">
   <link rel="import" type="css" href="privacy_page.css">
   <template>
     <settings-animated-pages id="pages" current-route="{{currentRoute}}"
diff --git a/chrome/browser/resources/settings/reset_page/powerwash_dialog.html b/chrome/browser/resources/settings/reset_page/powerwash_dialog.html
index fa650541..824b52d 100644
--- a/chrome/browser/resources/settings/reset_page/powerwash_dialog.html
+++ b/chrome/browser/resources/settings/reset_page/powerwash_dialog.html
@@ -3,20 +3,31 @@
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-checkbox/paper-checkbox.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-dialog/paper-dialog.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button.html">
 
 <dom-module id="settings-powerwash-dialog">
+  <link rel="import" type="css" href="reset_page_dialog.css">
   <template>
     <paper-dialog modal id="dialog">
-      <h2 i18n-content="powerwashDialogTitle"></h2>
-      <div i18n-content="powerwashDialogBody"></div>
-      <div class="layout center horizontal" id="buttonContainer">
-        <paper-button i18n-content="learnMore"
-            on-tap="onLearnMoreTap_" id="learnMore"></paper-button>
-        <div class="layout center buttons flex-1">
-          <paper-button on-tap="onCancelTap_" id="cancel"
-              i18n-content="cancel"></paper-button>
-          <paper-button on-tap="onRestartTap_" id="powerwash"
-              i18n-content="powerwashDialogButton"></paper-button>
+      <div id="dialog-content">
+        <div class="dialog-top-row">
+          <span class="dialog-title" i18n-content="powerwashDialogTitle"></span>
+          <paper-icon-button icon="clear" on-tap="onCancelTap_" id="close">
+          </paper-icon-button>
+        </div>
+        <div class="dialog-body">
+          <div class="explanation">
+            <span i18n-content="powerwashDialogExplanation"></span>
+            <a i18n-values="href:powerwashLearnMoreUrl"
+                i18n-content="learnMore" target="_blank"></a>
+          </div>
+          <div class="button-container">
+            <paper-button class="cancel-button" on-tap="onCancelTap_"
+                id="cancel" i18n-content="cancel"></paper-button>
+            <paper-button class="action-button" id="powerwash"
+                on-tap="onRestartTap_" i18n-content="powerwashDialogButton">
+            </paper-button>
+          </div>
         </div>
       </div>
     </paper-dialog>
diff --git a/chrome/browser/resources/settings/reset_page/powerwash_dialog.js b/chrome/browser/resources/settings/reset_page/powerwash_dialog.js
index cd8ebca5..b55bd9e 100644
--- a/chrome/browser/resources/settings/reset_page/powerwash_dialog.js
+++ b/chrome/browser/resources/settings/reset_page/powerwash_dialog.js
@@ -27,9 +27,4 @@
   onRestartTap_: function() {
     chrome.send('requestFactoryResetRestart');
   },
-
-  /** @private */
-  onLearnMoreTap_: function() {
-    window.open(loadTimeData.getString('powerwashLearnMoreUrl'));
-  },
 });
diff --git a/chrome/browser/resources/settings/reset_page/reset_page.html b/chrome/browser/resources/settings/reset_page/reset_page.html
index e4eaa234..ac6b8147 100644
--- a/chrome/browser/resources/settings/reset_page/reset_page.html
+++ b/chrome/browser/resources/settings/reset_page/reset_page.html
@@ -7,7 +7,7 @@
 
 <dom-module id="settings-reset-page">
   <link rel="import" type="css"
-      href="chrome://md-settings/settings_page/settings_page.css">
+      href="chrome://md-settings/settings_shared.css">
   <template>
     <div class="settings-box" id="resetProfile"
         on-tap="onShowResetProfileDialog_">
diff --git a/chrome/browser/resources/settings/reset_page/reset_page_dialog.css b/chrome/browser/resources/settings/reset_page/reset_page_dialog.css
new file mode 100644
index 0000000..9bdac00e
--- /dev/null
+++ b/chrome/browser/resources/settings/reset_page/reset_page_dialog.css
@@ -0,0 +1,64 @@
+/* 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. */
+
+#dialog-content {
+  -webkit-padding-end: 0;
+  -webkit-padding-start: 0;
+  margin-top: 0;
+}
+
+.dialog-top-row {
+  align-items: center;
+  border-bottom: 1px solid gainsboro;
+  display: flex;
+  padding-bottom: 5px;
+  padding-top: 5px;
+}
+
+.dialog-title {
+  flex: 1;
+  font-size: 1.13em;
+}
+
+.dialog-body {
+  font-size: 1em;
+  margin: 20px 0;
+}
+
+.dialog-title,
+.dialog-body {
+  -webkit-padding-end: 24px;
+  -webkit-padding-start: 24px;
+}
+
+.action-button {
+  -webkit-margin-start: 10px;
+  background-color: rgb(66, 133, 244);
+  color: white;
+  font-weight: 500;
+}
+
+.cancel-button {
+  color: rgb(109, 109, 109);
+  font-weight: 500;
+}
+
+paper-button {
+  margin: 0;
+}
+
+a {
+  color: rgb(66, 133, 244);
+  text-decoration: none;
+}
+
+.explanation {
+  margin-bottom: 35px;
+}
+
+.button-container {
+  display: flex;
+  flex: 1;
+  justify-content: flex-end;
+}
diff --git a/chrome/browser/resources/settings/reset_page/reset_profile_dialog.css b/chrome/browser/resources/settings/reset_page/reset_profile_dialog.css
index 665657934..805be9c 100644
--- a/chrome/browser/resources/settings/reset_page/reset_profile_dialog.css
+++ b/chrome/browser/resources/settings/reset_page/reset_profile_dialog.css
@@ -7,27 +7,6 @@
   width: 500px;
 }
 
-#reset {
-  -webkit-margin-start: 10px;
-  -webkit-padding-end: 15px;
-  -webkit-padding-start: 15px;
-  background-color: rgb(120, 120, 120);
-  color: white;
-}
-
-#learnMore,
-#cancel {
-  color: rgb(94, 94, 94);
-}
-
-#explanation {
-  margin: 10px 0;
-}
-
-#buttonContainer {
-  margin: 15px 0;
-}
-
 #feedbackBar {
   background-color: rgb(236, 236, 236);
   margin: 0;
diff --git a/chrome/browser/resources/settings/reset_page/reset_profile_dialog.html b/chrome/browser/resources/settings/reset_page/reset_profile_dialog.html
index 2a1a57a..6d164ac 100644
--- a/chrome/browser/resources/settings/reset_page/reset_profile_dialog.html
+++ b/chrome/browser/resources/settings/reset_page/reset_profile_dialog.html
@@ -3,24 +3,32 @@
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-checkbox/paper-checkbox.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-dialog/paper-dialog.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-spinner/paper-spinner.html">
 
 <dom-module id="settings-reset-profile-dialog">
+  <link rel="import" type="css" href="reset_page_dialog.css">
   <link rel="import" type="css" href="reset_profile_dialog.css">
   <template>
     <paper-dialog modal id="dialog">
-      <div>
-        <h2 i18n-content="resetPageTitle"></h2>
-        <div i18n-content="resetPageExplanation" id="explanation"></div>
-        <div class="layout center horizontal" id="buttonContainer">
-          <paper-button on-tap="onLearnMoreTap_" id="learnMore"
-              i18n-content="learnMore"></paper-button>
-          <div class="layout center buttons flex-1">
+      <div id="dialog-content">
+        <div class="dialog-top-row">
+          <span class="dialog-title" i18n-content="resetPageTitle"></span>
+          <paper-icon-button icon="clear" on-tap="onCancelTap_" id="close">
+          </paper-icon-button>
+        </div>
+        <div class="dialog-body">
+          <div class="explanation">
+            <span i18n-content="resetPageExplanation"></span>
+            <a i18n-values="href:resetPageLearnMoreUrl"
+                i18n-content="learnMore" target="_blank"></a>
+          </div>
+          <div class="button-container">
             <paper-spinner id="resetSpinner"></paper-spinner>
-            <paper-button on-tap="onCancelTap_" id="cancel"
-                i18n-content="cancel"></paper-button>
-            <paper-button i18n-content="resetPageCommit" on-tap="onResetTap_"
-                id="reset"></paper-button>
+            <paper-button class="cancel-button" on-tap="onCancelTap_"
+                id="cancel" i18n-content="cancel"></paper-button>
+            <paper-button class="action-button" i18n-content="resetPageCommit"
+                on-tap="onResetTap_" id="reset"></paper-button>
           </div>
         </div>
       </div>
diff --git a/chrome/browser/resources/settings/reset_page/reset_profile_dialog.js b/chrome/browser/resources/settings/reset_page/reset_profile_dialog.js
index 3fe767d..9ba069b 100644
--- a/chrome/browser/resources/settings/reset_page/reset_profile_dialog.js
+++ b/chrome/browser/resources/settings/reset_page/reset_profile_dialog.js
@@ -53,11 +53,6 @@
   },
 
   /** @private */
-  onLearnMoreTap_: function() {
-    window.open(loadTimeData.getString('resetPageLearnMoreUrl'));
-  },
-
-  /** @private */
   onSendSettingsChange_: function() {
     // TODO(dpapad): Update how settings info is surfaced when final mocks
     // exist.
diff --git a/chrome/browser/resources/settings/search_engines_page/search_engines_page.html b/chrome/browser/resources/settings/search_engines_page/search_engines_page.html
index f457aab2..184dd5b 100644
--- a/chrome/browser/resources/settings/search_engines_page/search_engines_page.html
+++ b/chrome/browser/resources/settings/search_engines_page/search_engines_page.html
@@ -3,7 +3,7 @@
 <link rel="import" href="search_engines_list.html">
 
 <dom-module id="settings-search-engines-page">
-  <link rel="import" type="css" href="chrome://md-settings/settings_page/settings_page.css">
+  <link rel="import" type="css" href="chrome://md-settings/settings_shared.css">
   <template>
     <div class="settings-box">
       <cr-search-engine-adder></cr-search-engine-adder>
diff --git a/chrome/browser/resources/settings/search_page/search_page.html b/chrome/browser/resources/settings/search_page/search_page.html
index dc879f55..3891b40 100644
--- a/chrome/browser/resources/settings/search_page/search_page.html
+++ b/chrome/browser/resources/settings/search_page/search_page.html
@@ -8,7 +8,7 @@
 
 <dom-module id="settings-search-page">
   <link rel="import" type="css"
-      href="chrome://md-settings/settings_page/settings_page.css">
+      href="chrome://md-settings/settings_shared.css">
   <link rel="import" type="css" href="search_page.css">
   <template>
     <settings-animated-pages id="pages" current-route="{{currentRoute}}"
diff --git a/chrome/browser/resources/settings/settings_resources.grd b/chrome/browser/resources/settings/settings_resources.grd
index 7723bac2..27e2192 100644
--- a/chrome/browser/resources/settings/settings_resources.grd
+++ b/chrome/browser/resources/settings/settings_resources.grd
@@ -127,8 +127,8 @@
       <structure name="IDR_SETTINGS_CR_SETTINGS_SUBHEADER_JS"
                  file="settings_page/settings_subheader.js"
                  type="chrome_html" />
-      <structure name="IDR_SETTINGS_CR_SETTINGS_PAGE_CSS"
-                 file="settings_page/settings_page.css"
+      <structure name="IDR_SETTINGS_CR_SETTINGS_SHARED_CSS"
+                 file="settings_shared.css"
                  type="chrome_html" />
       <structure name="IDR_SETTINGS_BREADCRUMB_CSS"
                  file="settings_ui/breadcrumb.css"
@@ -232,6 +232,9 @@
       <structure name="IDR_SETTINGS_POWERWASH_DIALOG_JS"
                  file="reset_page/powerwash_dialog.js"
                  type="chrome_html" />
+      <structure name="IDR_SETTINGS_RESET_PAGE_DIALOG_CSS"
+                 file="reset_page/reset_page_dialog.css"
+                 type="chrome_html" />
       <structure name="IDR_SETTINGS_RESET_PAGE_HTML"
                  file="reset_page/reset_page.html"
                  type="chrome_html"
@@ -253,7 +256,9 @@
                  type="chrome_html" />
       <structure name="IDR_SETTINGS_LANGUAGES_JS"
                  file="languages_page/languages.js"
-                 type="chrome_html" />
+                 type="chrome_html"
+                 flattenhtml="true"
+                 allowexternalscript="true" />
       <structure name="IDR_SETTINGS_LANGUAGES_PAGE_CSS"
                  file="languages_page/languages_page.css"
                  type="chrome_html" />
@@ -286,7 +291,9 @@
                  allowexternalscript="true" />
       <structure name="IDR_SETTINGS_LANGUAGES_LANGUAGE_DETAIL_PAGE_JS"
                  file="languages_page/language_detail_page.js"
-                 type="chrome_html" />
+                 type="chrome_html"
+                 flattenhtml="true"
+                 allowexternalscript="true" />
       <if expr="not is_macosx">
         <structure name="IDR_SETTINGS_LANGUAGES_EDIT_DICTIONARY_PAGE_CSS"
                    file="languages_page/edit_dictionary_page.css"
diff --git a/chrome/browser/resources/settings/settings_page/settings_page.css b/chrome/browser/resources/settings/settings_shared.css
similarity index 65%
rename from chrome/browser/resources/settings/settings_page/settings_page.css
rename to chrome/browser/resources/settings/settings_shared.css
index c4db693d..1ea45da 100644
--- a/chrome/browser/resources/settings/settings_page/settings_page.css
+++ b/chrome/browser/resources/settings/settings_shared.css
@@ -4,31 +4,8 @@
 
 /**
  * @fileoverview
- * Common styles for Settings pages.
+ * Common styles for Material Design settings.
  */
-:host > paper-material {
-  -webkit-padding-start: 80px;
-  background-color: white;
-  display: flex;
-  flex-direction: column;
-  padding: 40px;
-}
-
-.soft-border {
-  border: 1px solid #c4c4c4;
-  border-radius: 2px;
-}
-
-.page-content {
-  width: 760px;
-}
-
-settings-checkbox {
-  -webkit-margin-end: 10px;
-  -webkit-margin-start: 0;
-  margin-bottom: 10px;
-  margin-top: 10px;
-}
 
 paper-button {
   margin: 0;
@@ -36,7 +13,7 @@
 }
 
 paper-button[toggles][active] {
-  background-color: lightgrey;
+  background-color: LightGray;
 }
 
 h2 {
@@ -52,6 +29,10 @@
   margin-top: 25px;
 }
 
+.button-strip {
+  text-align: end;
+}
+
 .settings-box {
   @apply(--layout-center);
   border-top: 1px solid #e0e0e0;
@@ -76,7 +57,3 @@
   /* Same padding as paper-icon-button. */
   padding: 8px;
 }
-
-.button-strip {
-  text-align: end;
-}
diff --git a/chrome/browser/resources/settings/signin_page/signin_page.html b/chrome/browser/resources/settings/signin_page/signin_page.html
index 42bb0124..e74f5c4 100644
--- a/chrome/browser/resources/settings/signin_page/signin_page.html
+++ b/chrome/browser/resources/settings/signin_page/signin_page.html
@@ -11,40 +11,57 @@
 
 <dom-module id="settings-signin-page">
   <link rel="import" type="css"
-      href="chrome://md-settings/settings_page/settings_page.css">
+      href="chrome://md-settings/settings_shared.css">
   <template>
     <settings-animated-pages id="pages" current-route="{{currentRoute}}"
         section="people">
       <neon-animatable id="main">
-        <div class="settings-box split" hidden="[[!isStatusTextSet_(syncStatus)]]">
+        <div class="settings-box">
+          <div class="split">
+            <span class="start">
+              <!-- TODO(tommycli): Show current profile icon and name here.
+                                   To be done by December 2015. -->
+            </span>
+            <span>
+              <template is="dom-if" if="[[!syncStatus.signedIn]]">
+                <paper-button on-tap="onSigninTap_" raised
+                    disabled="[[syncStatus.setupInProgress]]">
+                    [[i18n('syncSignin')]]
+                </paper-button>
+              </template>
+              <template is="dom-if" if="[[syncStatus.signedIn]]">
+                <paper-button on-tap="onDisconnectTap_"
+                    disabled="[[syncStatus.setupInProgress]]">
+                    [[i18n('syncDisconnect')]]
+                </paper-button>
+              </template>
+            </span>
+          </div>
+          <div hidden="[[syncStatus.signedIn]]">[[i18n('syncOverview')]]</div>
+        </div>
+
+        <div class="settings-box split"
+            hidden="[[!isStatusTextSet_(syncStatus)]]">
           <span id="syncStatusText"></span>
           <paper-button on-tap="onActionLinkTap_">
             [[syncStatus.actionLinkText]]
           </paper-button>
         </div>
 
-        <template is="dom-if" if="[[!syncStatus.signedIn]]">
-          <div class="settings-box">[[i18n('syncOverview')]]</div>
-          <div class="settings-box button-strip">
-            <paper-button on-tap="onSigninTap_" raised
-                disabled="[[syncStatus.setupInProgress]]">
-                [[i18n('syncSignin')]]
-            </paper-button>
-          </div>
-        </template>
-        <template is="dom-if" if="[[syncStatus.signedIn]]">
-          <paper-button on-tap="onDisconnectTap_" raised
-              disabled="[[syncStatus.setupInProgress]]">
-              [[i18n('syncDisconnect')]]
-          </paper-button>
-
-          <template is="dom-if"
-              if="[[isAdvancedSyncSettingsVisible_(syncStatus)]]">
+        <template is="dom-if"
+            if="[[isAdvancedSyncSettingsVisible_(syncStatus)]]">
+          <div class="settings-box">
             <paper-button on-tap="onSyncTap_" raised>
               [[i18n('syncPageTitle')]]
             </paper-button>
-          </template>
+          </div>
         </template>
+
+        <div class="settings-box">
+          <paper-button i18n-content="manageOtherPeople"
+              on-tap="onManageOtherPeople_">
+          </paper-button>
+        </div>
       </neon-animatable>
       <neon-animatable id="sync">
         <settings-subheader i18n-values="page-title:syncPageTitle">
diff --git a/chrome/browser/resources/settings/signin_page/signin_page.js b/chrome/browser/resources/settings/signin_page/signin_page.js
index c4ea9f7..5be01225 100644
--- a/chrome/browser/resources/settings/signin_page/signin_page.js
+++ b/chrome/browser/resources/settings/signin_page/signin_page.js
@@ -84,21 +84,25 @@
     this.$.pages.setSubpageChain(['sync']);
   },
 
-  /**
-   * @private
-   * @return {boolean}
-   */
-  isStatusTextSet_: function() {
-    return this.syncStatus && this.syncStatus.statusText.length > 0;
+  /** @private */
+  onManageOtherPeople_: function() {
+    settings.SyncPrivateApi.manageOtherPeople();
   },
 
   /**
    * @private
    * @return {boolean}
    */
-  isAdvancedSyncSettingsVisible_: function() {
-    var status = this.syncStatus;
-    return status && status.signedIn && !status.managed &&
-           status.syncSystemEnabled;
+  isStatusTextSet_: function(syncStatus) {
+    return syncStatus && syncStatus.statusText.length > 0;
+  },
+
+  /**
+   * @private
+   * @return {boolean}
+   */
+  isAdvancedSyncSettingsVisible_: function(syncStatus) {
+    return syncStatus && syncStatus.signedIn && !syncStatus.managed &&
+           syncStatus.syncSystemEnabled;
   },
 });
diff --git a/chrome/browser/resources/settings/site_settings/site_details.html b/chrome/browser/resources/settings/site_settings/site_details.html
index 0c50fcdc..33d96f7 100644
--- a/chrome/browser/resources/settings/site_settings/site_details.html
+++ b/chrome/browser/resources/settings/site_settings/site_details.html
@@ -6,7 +6,7 @@
 
 <dom-module id="site-details">
   <link rel="import" type="css"
-      href="chrome://md-settings/settings_page/settings_page.css">
+      href="chrome://md-settings/settings_shared.css">
   <link rel="import" type="css" href="site_details.css">
   <template>
     <div class="settings-box">
diff --git a/chrome/browser/resources/settings/site_settings/site_details_permission.html b/chrome/browser/resources/settings/site_settings/site_details_permission.html
index d99e49a0..ba54d4eb 100644
--- a/chrome/browser/resources/settings/site_settings/site_details_permission.html
+++ b/chrome/browser/resources/settings/site_settings/site_details_permission.html
@@ -12,7 +12,7 @@
 
 <dom-module id="site-details-permission">
   <link rel="import" type="css"
-      href="chrome://md-settings/settings_page/settings_page.css">
+      href="chrome://md-settings/settings_shared.css">
   <link rel="import" type="css" href="site_details_permission.css">
   <template>
     <div id="details" class="horizontal layout top" hidden>
diff --git a/chrome/browser/resources/settings/site_settings/site_list.html b/chrome/browser/resources/settings/site_settings/site_list.html
index 2c0ae8337..51414d1 100644
--- a/chrome/browser/resources/settings/site_settings/site_list.html
+++ b/chrome/browser/resources/settings/site_settings/site_list.html
@@ -13,7 +13,7 @@
 <link rel="import" href="chrome://md-settings/site_settings/site_settings_behavior.html">
 
 <dom-module id="settings-site-list">
-  <link rel="import" type="css" href="../settings_page/settings_page.css">
+  <link rel="import" type="css" href="../settings_shared.css">
   <link rel="import" type="css" href="site_list.css">
   <template>
     <paper-submenu id="category" hidden on-paper-submenu-open="onToggle_"
diff --git a/chrome/browser/resources/settings/site_settings/site_settings_category.html b/chrome/browser/resources/settings/site_settings/site_settings_category.html
index 829ba97..268d93db 100644
--- a/chrome/browser/resources/settings/site_settings/site_settings_category.html
+++ b/chrome/browser/resources/settings/site_settings/site_settings_category.html
@@ -16,7 +16,7 @@
 
 <dom-module id="site-settings-category">
   <link rel="import" type="css"
-      href="chrome://md-settings/settings_page/settings_page.css">
+      href="chrome://md-settings/settings_shared.css">
   <link rel="import" type="css" href="site_settings_category.css">
   <template>
     <settings-animated-pages id="pages" current-route="{{currentRoute}}"
diff --git a/chrome/browser/resources/settings/sync_page/sync_page.css b/chrome/browser/resources/settings/sync_page/sync_page.css
index 1e47219e..3b2eda89 100644
--- a/chrome/browser/resources/settings/sync_page/sync_page.css
+++ b/chrome/browser/resources/settings/sync_page/sync_page.css
@@ -2,21 +2,18 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file. */
 
+paper-checkbox {
+  margin-bottom: 10px;
+}
+
 paper-radio-button {
   display: block;
 }
 
-.checkbox-container {
-  display: flex;
-  flex-flow: column;
+#sync-item-list {
+  margin-left: 32px;
 }
 
-.checkbox-container-row {
-  display: flex;
-}
-
-.checkbox-container-row > paper-checkbox {
-  display: flex;
-  flex-basis: 0;
-  flex-grow: 1;
+#sync-item-list paper-checkbox {
+  display: block;
 }
diff --git a/chrome/browser/resources/settings/sync_page/sync_page.html b/chrome/browser/resources/settings/sync_page/sync_page.html
index e01921a..ca62faed 100644
--- a/chrome/browser/resources/settings/sync_page/sync_page.html
+++ b/chrome/browser/resources/settings/sync_page/sync_page.html
@@ -12,72 +12,60 @@
 
 <dom-module id="settings-sync-page">
   <link rel="import" type="css"
-      href="chrome://md-settings/settings_page/settings_page.css">
+      href="chrome://md-settings/settings_shared.css">
   <link rel="import" type="css" href="sync_page.css">
   <template>
     <iron-pages id="pages" selected="loading" attr-for-selected="id">
       <div id="loading" i18n-content="syncLoading"></div>
       <div id="timeout" i18n-content="syncTimeout"></div>
       <div id="main">
-        <paper-dropdown-menu>
-          <paper-menu id="syncSelector" class="dropdown-content"
-              selected="[[selectedSyncSelectorIndex_(syncPrefs.syncAllDataTypes)]]"
-              on-iron-select="onSyncSelectorChanged_">
-            <paper-item name="sync-everything"
-                i18n-content="syncEverythingMenuOption">
-            </paper-item>
-            <paper-item name="choose-what-to-sync"
-                i18n-content="chooseWhatToSyncMenuOption">
-            </paper-item>
-          </paper-menu>
-        </paper-dropdown-menu>
+        <div class="settings-box">
+          <paper-checkbox checked="{{syncPrefs.syncAllDataTypes}}"
+              on-change="onSyncAllDataTypesChanged_">
+            <span i18n-content="syncEverythingCheckboxLabel">
+          </paper-checkbox>
 
-        <div class="checkbox-container">
-          <div class="checkbox-container-row">
+          <div id="sync-item-list">
             <paper-checkbox checked="{{syncPrefs.appsSynced}}"
                 hidden="[[!syncPrefs.appsRegistered]]"
                 disabled="[[shouldSyncCheckboxBeDisabled_(syncPrefs.syncAllDataTypes, syncPrefs.appsEnforced)]]">
               <span i18n-content="appCheckboxLabel"></span>
             </paper-checkbox>
+            <paper-checkbox checked="{{syncPrefs.autofillSynced}}"
+                hidden="[[!syncPrefs.autofillRegistered]]"
+                disabled="[[shouldSyncCheckboxBeDisabled_(syncPrefs.syncAllDataTypes, syncPrefs.autofillEnforced)]]">
+              <span i18n-content="autofillCheckboxLabel"></span>
+            </paper-checkbox>
+            <paper-checkbox checked="{{syncPrefs.bookmarksSynced}}"
+                hidden="[[!syncPrefs.bookmarksRegistered]]"
+                disabled="[[shouldSyncCheckboxBeDisabled_(syncPrefs.syncAllDataTypes, syncPrefs.bookmarksEnforced)]]">
+              <span i18n-content="bookmarksCheckboxLabel"></span>
+            </paper-checkbox>
             <paper-checkbox checked="{{syncPrefs.extensionsSynced}}"
                 hidden="[[!syncPrefs.extensionsRegistered]]"
                 disabled="[[shouldSyncCheckboxBeDisabled_(syncPrefs.syncAllDataTypes, syncPrefs.extensionsEnforced)]]">
               <span i18n-content="extensionsCheckboxLabel"></span>
             </paper-checkbox>
-            <paper-checkbox checked="{{syncPrefs.preferencesSynced}}"
-                hidden="[[!syncPrefs.preferencesRegistered]]"
-                disabled="[[shouldSyncCheckboxBeDisabled_(syncPrefs.syncAllDataTypes, syncPrefs.preferencesEnforced)]]">
-              <span i18n-content="settingsCheckboxLabel"></span>
-            </paper-checkbox>
-          </div>
-          <div class="checkbox-container-row">
-            <paper-checkbox checked="{{syncPrefs.autofillSynced}}"
-                hidden="[[!syncPrefs.autofillRegistered]]"
-                disabled="[[shouldSyncCheckboxBeDisabled_(syncPrefs.syncAllDataTypes, syncPrefs.autofillEnforced)]]">
-              <span i18n-content="autofillCheckboxLabel"></span>
-            </paper-checkbox>
             <paper-checkbox checked="{{syncPrefs.typedUrlsSynced}}"
                 hidden="[[!syncPrefs.typedUrlsRegistered]]"
                 disabled="[[shouldSyncCheckboxBeDisabled_(syncPrefs.syncAllDataTypes, syncPrefs.typedUrlsEnforced)]]">
               <span i18n-content="historyCheckboxLabel"></span>
             </paper-checkbox>
-            <paper-checkbox checked="{{syncPrefs.themesSynced}}"
-                hidden="[[!syncPrefs.themesRegistered]]"
-                disabled="[[shouldSyncCheckboxBeDisabled_(syncPrefs.syncAllDataTypes, syncPrefs.themesEnforced)]]">
-              <span i18n-content="themesAndWallpapersCheckboxLabel"></span>
-            </paper-checkbox>
-          </div>
-          <div class="checkbox-container-row">
-            <paper-checkbox checked="{{syncPrefs.bookmarksSynced}}"
-                hidden="[[!syncPrefs.bookmarksRegistered]]"
-                disabled="[[shouldSyncCheckboxBeDisabled_(syncPrefs.syncAllDataTypes, syncPrefs.bookmarksEnforced)]]">
-              <span i18n-content="bookmarksCheckboxLabel"></span>
-            </paper-checkbox>
             <paper-checkbox checked="{{syncPrefs.passwordsSynced}}"
                 hidden="[[!syncPrefs.passwordsRegistered]]"
                 disabled="[[shouldSyncCheckboxBeDisabled_(syncPrefs.syncAllDataTypes, syncPrefs.passwordsEnforced)]]">
               <span i18n-content="passwordsCheckboxLabel"></span>
             </paper-checkbox>
+            <paper-checkbox checked="{{syncPrefs.preferencesSynced}}"
+                hidden="[[!syncPrefs.preferencesRegistered]]"
+                disabled="[[shouldSyncCheckboxBeDisabled_(syncPrefs.syncAllDataTypes, syncPrefs.preferencesEnforced)]]">
+              <span i18n-content="settingsCheckboxLabel"></span>
+            </paper-checkbox>
+            <paper-checkbox checked="{{syncPrefs.themesSynced}}"
+                hidden="[[!syncPrefs.themesRegistered]]"
+                disabled="[[shouldSyncCheckboxBeDisabled_(syncPrefs.syncAllDataTypes, syncPrefs.themesEnforced)]]">
+              <span i18n-content="themesAndWallpapersCheckboxLabel"></span>
+            </paper-checkbox>
             <paper-checkbox checked="{{syncPrefs.tabsSynced}}"
                 hidden="[[!syncPrefs.tabsRegistered]]"
                 disabled="[[shouldSyncCheckboxBeDisabled_(syncPrefs.syncAllDataTypes, syncPrefs.tabsEnforced)]]">
@@ -86,54 +74,50 @@
           </div>
         </div>
 
-        <h2 i18n-content="encryptionOptionsTitle"></h2>
-        <p i18n-content="syncDataEncryptedText"></p>
+        <div class="settings-box">
+          <h2 i18n-content="encryptionOptionsTitle"></h2>
+          <p i18n-content="syncDataEncryptedText"></p>
 
-        <template is="dom-if" if="[[!syncPrefs.showPassphrase]]">
-          <paper-radio-group id="encryptRadioGroup"
-              selected="[[selectedEncryptionRadio_(syncPrefs.usePassphrase, syncPrefs.encryptAllData)]]"
-              on-paper-radio-group-changed="onEncryptionRadioSelectionChanged_">
-            <paper-radio-button name="encrypt-with-google"
-                disabled="[[encryptionRadiosDisabled_(syncPrefs.usePassphrase, syncPrefs.encryptAllData)]]">
-              <span>[[i18n('encryptWithGoogleCredentialsLabel')]]</span>
-            </paper-radio-button>
-            <paper-radio-button name="encrypt-with-passphrase"
-                disabled="[[encryptionRadiosDisabled_(syncPrefs.usePassphrase, syncPrefs.encryptAllData)]]">
-              <span>[[encryptWithPassphraseBody_(syncPrefs.fullEncryptionBody)]]</span>
-            </paper-radio-button>
-          </paper-radio-group>
-        </template>
+          <template is="dom-if" if="[[!syncPrefs.showPassphrase]]">
+            <paper-radio-group id="encryptRadioGroup"
+                selected="[[selectedEncryptionRadio_(syncPrefs.usePassphrase, syncPrefs.encryptAllData)]]"
+                on-paper-radio-group-changed="onEncryptionRadioSelectionChanged_">
+              <paper-radio-button name="encrypt-with-google"
+                  disabled="[[encryptionRadiosDisabled_(syncPrefs.usePassphrase, syncPrefs.encryptAllData)]]">
+                <span>[[i18n('encryptWithGoogleCredentialsLabel')]]</span>
+              </paper-radio-button>
+              <paper-radio-button name="encrypt-with-passphrase"
+                  disabled="[[encryptionRadiosDisabled_(syncPrefs.usePassphrase, syncPrefs.encryptAllData)]]">
+                <span>[[encryptWithPassphraseBody_(syncPrefs.fullEncryptionBody)]]</span>
+              </paper-radio-button>
+            </paper-radio-group>
+          </template>
 
-        <template is="dom-if" if="[[creatingNewPassphrase]]">
-          <div>[[i18n('passphraseExplanationText')]]</div>
-          <paper-input id="passphraseInput" type="password"
-              placeholder="[[i18n('passphrasePlaceholder')]]">
-          </paper-input>
-          <paper-input id="passphraseConfirmationInput" type="password"
-              placeholder="[[i18n('passphraseConfirmationPlaceholder')]]">
-          </paper-input>
-          <div id="emptyPassphraseError" hidden>[[i18n('emptyPassphraseError')]]</div>
-          <div id="mismatchedPassphraseError" hidden>[[i18n('mismatchedPassphraseError')]]</div>
-        </template>
+          <template is="dom-if" if="[[creatingNewPassphrase]]">
+            <div>[[i18n('passphraseExplanationText')]]</div>
+            <paper-input id="passphraseInput" type="password"
+                placeholder="[[i18n('passphrasePlaceholder')]]">
+            </paper-input>
+            <paper-input id="passphraseConfirmationInput" type="password"
+                placeholder="[[i18n('passphraseConfirmationPlaceholder')]]">
+            </paper-input>
+            <div id="emptyPassphraseError" hidden>[[i18n('emptyPassphraseError')]]</div>
+            <div id="mismatchedPassphraseError" hidden>[[i18n('mismatchedPassphraseError')]]</div>
+          </template>
 
-        <template is="dom-if" if="[[syncPrefs.showPassphrase]]">
-          <div id="askCustomPassphraseMessage"
-              hidden="[[askOldGooglePassphrase]]">[[syncPrefs.enterPassphraseBody]]</div>
-          <div id="askOldGooglePassphraseMessage"
-              hidden="[[!askOldGooglePassphrase]]">[[syncPrefs.enterGooglePassphraseBody]]</div>
-          <paper-input id="existingPassphraseInput" type="password"
-              placeholder="[[i18n('passphrasePlaceholder')]]">
-          </paper-input>
-          <div id="incorrectPassphraseError" hidden>[[i18n('incorrectPassphraseError')]]</div>
-        </template>
+          <template is="dom-if" if="[[syncPrefs.showPassphrase]]">
+            <div id="askCustomPassphraseMessage"
+                hidden="[[askOldGooglePassphrase]]">[[syncPrefs.enterPassphraseBody]]</div>
+            <div id="askOldGooglePassphraseMessage"
+                hidden="[[!askOldGooglePassphrase]]">[[syncPrefs.enterGooglePassphraseBody]]</div>
+            <paper-input id="existingPassphraseInput" type="password"
+                placeholder="[[i18n('passphrasePlaceholder')]]">
+            </paper-input>
+            <div id="incorrectPassphraseError" hidden>[[i18n('incorrectPassphraseError')]]</div>
+          </template>
+        </div>
 
-        <div class="button-row">
-          <div class="flex">
-            <paper-button i18n-content="useDefaultSettingsButton"
-                on-tap="onUseDefaultsTap_"
-                hidden="[[syncPrefs.showPassphrase]]">
-            </paper-button>
-          </div>
+        <div class="settings-box">
           <paper-button i18n-content="cancelButton" on-tap="onCancelTap_">
           </paper-button>
           <paper-button i18n-content="okButton" on-tap="onOkTap_" raised>
diff --git a/chrome/browser/resources/settings/sync_page/sync_page.js b/chrome/browser/resources/settings/sync_page/sync_page.js
index c50064e..f8f436f 100644
--- a/chrome/browser/resources/settings/sync_page/sync_page.js
+++ b/chrome/browser/resources/settings/sync_page/sync_page.js
@@ -5,15 +5,6 @@
 (function() {
 
 /**
- * Indices of the options in the sync selector menu.
- * @enum {number}
- */
-var SyncSelectorIndices = {
-  SYNC_EVERYTHING: 0,
-  CHOOSE_WHAT_TO_SYNC: 1,
-};
-
-/**
  * Names of the radio buttons which allow the user to choose his encryption
  * mechanism.
  * @enum {string}
@@ -125,6 +116,26 @@
     this.$.pages.selected = 'main';
   },
 
+  /**
+   * Handler for when the sync all data types checkbox is changed.
+   * @param {Event} event
+   * @private
+   */
+  onSyncAllDataTypesChanged_: function(event) {
+    if (event.target.checked) {
+      this.set('syncPrefs.syncAllDataTypes', true);
+      this.set('syncPrefs.appsSynced', true);
+      this.set('syncPrefs.extensionsSynced', true);
+      this.set('syncPrefs.preferencesSynced', true);
+      this.set('syncPrefs.autofillSynced', true);
+      this.set('syncPrefs.typedUrlsSynced', true);
+      this.set('syncPrefs.themesSynced', true);
+      this.set('syncPrefs.bookmarksSynced', true);
+      this.set('syncPrefs.passwordsSynced', true);
+      this.set('syncPrefs.tabsSynced', true);
+    }
+  },
+
   /** @private */
   onCancelTap_: function() {
     // Event is caught by settings-animated-pages.
@@ -161,23 +172,6 @@
   },
 
   /**
-   * Applies the default settings (i.e., sync everything).
-   * @private
-   */
-  onUseDefaultsTap_: function() {
-    this.set('syncPrefs.syncAllDataTypes', true);
-    this.set('syncPrefs.appsSynced', true);
-    this.set('syncPrefs.extensionsSynced', true);
-    this.set('syncPrefs.preferencesSynced', true);
-    this.set('syncPrefs.autofillSynced', true);
-    this.set('syncPrefs.typedUrlsSynced', true);
-    this.set('syncPrefs.themesSynced', true);
-    this.set('syncPrefs.bookmarksSynced', true);
-    this.set('syncPrefs.passwordsSynced', true);
-    this.set('syncPrefs.tabsSynced', true);
-  },
-
-  /**
    * Callback invoked from calling settings.SyncPrivateApi.setSyncPrefs().
    * @param {!settings.PageStatus} callbackState
    * @private
@@ -203,16 +197,6 @@
   },
 
   /**
-   * Computed binding returning the selected index for the sync dropdown.
-   * @private
-   */
-  selectedSyncSelectorIndex_: function() {
-    return this.syncPrefs.syncAllDataTypes ?
-        SyncSelectorIndices.SYNC_EVERYTHING :
-        SyncSelectorIndices.CHOOSE_WHAT_TO_SYNC;
-  },
-
-  /**
    * Computed binding returning the selected encryption radio button.
    * @private
    */
@@ -242,17 +226,6 @@
   },
 
   /**
-   * Handler for when the sync selector menu has changed its active option.
-   * @private
-   */
-  onSyncSelectorChanged_: function(event) {
-    if (event.target.selected == SyncSelectorIndices.SYNC_EVERYTHING)
-      this.onUseDefaultsTap_();
-    else
-      this.set('syncPrefs.syncAllDataTypes', false);
-  },
-
-  /**
    * @param {boolean} syncAllDataTypes
    * @param {boolean} enforced
    * @return {boolean} Whether the sync checkbox should be disabled.
diff --git a/chrome/browser/resources/settings/sync_page/sync_private_api.js b/chrome/browser/resources/settings/sync_page/sync_private_api.js
index e9e9433..35a330f 100644
--- a/chrome/browser/resources/settings/sync_page/sync_private_api.js
+++ b/chrome/browser/resources/settings/sync_page/sync_private_api.js
@@ -202,6 +202,13 @@
   };
 
   /**
+   * Sends a request from JS to C++ to open the multi-profile User Manager.
+   */
+  SyncPrivateApi.manageOtherPeople = function() {
+    chrome.send('SyncSetupManageOtherPeople');
+  };
+
+  /**
    * This function encapsulates the logic that maps from the legacy
    * SyncSettingsHandler to an API natural to the new Polymer implementation.
    * @param {!settings.PageStatus} status
diff --git a/chrome/browser/resources/settings/users_page/user_list.css b/chrome/browser/resources/settings/users_page/user_list.css
index bd4ee80..0db441cd 100644
--- a/chrome/browser/resources/settings/users_page/user_list.css
+++ b/chrome/browser/resources/settings/users_page/user_list.css
@@ -11,6 +11,11 @@
   width: 18px;
 }
 
+.soft-border {
+  border: 1px solid #c4c4c4;
+  border-radius: 2px;
+}
+
 .user {
   -webkit-padding-end: 8px;
   -webkit-padding-start: 20px;
diff --git a/chrome/browser/resources/settings/users_page/user_list.html b/chrome/browser/resources/settings/users_page/user_list.html
index 88f1bf52..579424d 100644
--- a/chrome/browser/resources/settings/users_page/user_list.html
+++ b/chrome/browser/resources/settings/users_page/user_list.html
@@ -4,7 +4,7 @@
 
 <dom-module id="settings-user-list">
   <link rel="import" type="css"
-      href="chrome://md-settings/settings_page/settings_page.css">
+      href="chrome://md-settings/settings_shared.css">
   <link rel="import" type="css" href="user_list.css">
   <template>
     <div class="user-list soft-border">
diff --git a/chrome/browser/resources/settings/users_page/users_page.html b/chrome/browser/resources/settings/users_page/users_page.html
index 2f33ad1..86343c7 100644
--- a/chrome/browser/resources/settings/users_page/users_page.html
+++ b/chrome/browser/resources/settings/users_page/users_page.html
@@ -9,7 +9,7 @@
 
 <dom-module id="settings-users-page">
   <link rel="import" type="css"
-      href="chrome://md-settings/settings_page/settings_page.css">
+      href="chrome://md-settings/settings_shared.css">
   <link rel="import" type="css" href="users_page.css">
   <template>
     <div class="page-content">
diff --git a/chrome/browser/safe_browsing/client_side_detection_host.cc b/chrome/browser/safe_browsing/client_side_detection_host.cc
index 414c55b..ef73fb4 100644
--- a/chrome/browser/safe_browsing/client_side_detection_host.cc
+++ b/chrome/browser/safe_browsing/client_side_detection_host.cc
@@ -45,8 +45,6 @@
 const size_t ClientSideDetectionHost::kMaxUrlsPerIP = 20;
 const size_t ClientSideDetectionHost::kMaxIPsPerBrowse = 200;
 
-const char kSafeBrowsingMatchKey[] = "safe_browsing_match";
-
 typedef base::Callback<void(bool)> ShouldClassifyUrlCallback;
 
 // This class is instantiated each time a new toplevel URL loads, and
@@ -432,48 +430,11 @@
   unsafe_resource_->callback.Reset();  // Don't do anything stupid.
 }
 
-void ClientSideDetectionHost::OnSafeBrowsingMatch(
-    const SafeBrowsingUIManager::UnsafeResource& resource) {
-  if (!web_contents() || !web_contents()->GetController().GetActiveEntry())
-    return;
-
-  // Check that this notification is really for us.
-  content::RenderViewHost* hit_rvh = content::RenderViewHost::FromID(
-      resource.render_process_host_id, resource.render_view_id);
-  if (!hit_rvh ||
-      web_contents() != content::WebContents::FromRenderViewHost(hit_rvh))
-    return;
-
-  web_contents()->GetController().GetActiveEntry()->SetExtraData(
-      kSafeBrowsingMatchKey, base::ASCIIToUTF16("1"));
-}
-
 scoped_refptr<SafeBrowsingDatabaseManager>
 ClientSideDetectionHost::database_manager() {
   return database_manager_;
 }
 
-bool ClientSideDetectionHost::DidPageReceiveSafeBrowsingMatch() const {
-  if (!web_contents() || !web_contents()->GetController().GetVisibleEntry())
-    return false;
-
-  // If an interstitial page is showing, GetVisibleEntry will return the
-  // transient NavigationEntry for the interstitial. The transient entry
-  // will not have the flag set, so use the pending entry instead if there
-  // is one.
-  NavigationEntry* entry = web_contents()->GetController().GetPendingEntry();
-  if (!entry) {
-    entry = web_contents()->GetController().GetVisibleEntry();
-    if (entry->GetPageType() == content::PAGE_TYPE_INTERSTITIAL)
-      entry = web_contents()->GetController().GetLastCommittedEntry();
-    if (!entry)
-      return false;
-  }
-
-  base::string16 value;
-  return entry->GetExtraData(kSafeBrowsingMatchKey, &value);
-}
-
 void ClientSideDetectionHost::WebContentsDestroyed() {
   // Tell any pending classification request that it is being canceled.
   if (classification_request_.get()) {
diff --git a/chrome/browser/safe_browsing/client_side_detection_host.h b/chrome/browser/safe_browsing/client_side_detection_host.h
index d5673a2..ab26a38 100644
--- a/chrome/browser/safe_browsing/client_side_detection_host.h
+++ b/chrome/browser/safe_browsing/client_side_detection_host.h
@@ -52,17 +52,8 @@
   void OnSafeBrowsingHit(
       const SafeBrowsingUIManager::UnsafeResource& resource) override;
 
-  // Called when the SafeBrowsingService finds a match on the SB lists.
-  // Called on the UI thread. Called even if the resource is whitelisted.
-  void OnSafeBrowsingMatch(
-      const SafeBrowsingUIManager::UnsafeResource& resource) override;
-
   virtual scoped_refptr<SafeBrowsingDatabaseManager> database_manager();
 
-  // Returns whether the current page contains a malware or phishing safe
-  // browsing match.
-  bool DidPageReceiveSafeBrowsingMatch() const;
-
  protected:
   explicit ClientSideDetectionHost(content::WebContents* tab);
 
diff --git a/chrome/browser/safe_browsing/client_side_detection_host_unittest.cc b/chrome/browser/safe_browsing/client_side_detection_host_unittest.cc
index b3037a62..9d9fc09 100644
--- a/chrome/browser/safe_browsing/client_side_detection_host_unittest.cc
+++ b/chrome/browser/safe_browsing/client_side_detection_host_unittest.cc
@@ -364,11 +364,7 @@
         GetID();
     resource.render_view_id =
         web_contents()->GetRenderViewHost()->GetRoutingID();
-    ASSERT_FALSE(csd_host_->DidPageReceiveSafeBrowsingMatch());
-    csd_host_->OnSafeBrowsingMatch(resource);
-    ASSERT_TRUE(csd_host_->DidPageReceiveSafeBrowsingMatch());
     csd_host_->OnSafeBrowsingHit(resource);
-    ASSERT_TRUE(csd_host_->DidPageReceiveSafeBrowsingMatch());
     resource.callback.Reset();
     ASSERT_TRUE(csd_host_->DidShowSBInterstitial());
     TestUnsafeResourceCopied(resource);
@@ -397,17 +393,13 @@
         BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO);
     resource.render_process_host_id = pending_rvh()->GetProcess()->GetID();
     resource.render_view_id = pending_rvh()->GetRoutingID();
-    csd_host_->OnSafeBrowsingMatch(resource);
     csd_host_->OnSafeBrowsingHit(resource);
     resource.callback.Reset();
 
-    ASSERT_TRUE(csd_host_->DidPageReceiveSafeBrowsingMatch());
-
     // LoadURL created a navigation entry, now simulate the RenderView sending
     // a notification that it actually navigated.
     content::WebContentsTester::For(web_contents())->CommitPendingNavigation();
 
-    ASSERT_TRUE(csd_host_->DidPageReceiveSafeBrowsingMatch());
     ASSERT_TRUE(csd_host_->DidShowSBInterstitial());
     TestUnsafeResourceCopied(resource);
   }
@@ -423,11 +415,9 @@
       EXPECT_NE(web_contents()->GetRenderViewHost()->GetRoutingID(),
                 pending_rvh()->GetRoutingID());
     }
-    ASSERT_FALSE(csd_host_->DidPageReceiveSafeBrowsingMatch());
     ASSERT_FALSE(csd_host_->DidShowSBInterstitial());
 
     content::WebContentsTester::For(web_contents())->CommitPendingNavigation();
-    ASSERT_FALSE(csd_host_->DidPageReceiveSafeBrowsingMatch());
     ASSERT_FALSE(csd_host_->DidShowSBInterstitial());
   }
 
diff --git a/chrome/browser/safe_browsing/download_protection_service.cc b/chrome/browser/safe_browsing/download_protection_service.cc
index caf06c2..b6674564 100644
--- a/chrome/browser/safe_browsing/download_protection_service.cc
+++ b/chrome/browser/safe_browsing/download_protection_service.cc
@@ -707,19 +707,12 @@
       return;
     }
 
-// Currently, the UI is enabled on Windows, OSX and chrome OS. we don't ping
-// the server if we're not on one of those platforms.
-// TODO(noelutz): change this code once the UI is done for Linux.
-#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_CHROMEOS)
-    // The URLFetcher is owned by the UI thread, so post a message to
-    // start the pingback.
-    BrowserThread::PostTask(
-        BrowserThread::UI,
-        FROM_HERE,
-        base::Bind(&CheckClientDownloadRequest::GetTabRedirects, this));
-#else
-    PostFinishTask(UNKNOWN, REASON_OS_NOT_SUPPORTED);
-#endif
+  // The URLFetcher is owned by the UI thread, so post a message to
+  // start the pingback.
+  BrowserThread::PostTask(
+      BrowserThread::UI,
+      FROM_HERE,
+      base::Bind(&CheckClientDownloadRequest::GetTabRedirects, this));
   }
 
   void GetTabRedirects() {
@@ -1111,19 +1104,12 @@
 bool DownloadProtectionService::IsSupportedDownload(
     const content::DownloadItem& item,
     const base::FilePath& target_path) const {
-// Currently, the UI is only enabled on Windows, OSX and Chrome OS. On
-// Linux we still want to show the dangerous file type warning if the file
-// is possibly dangerous which means we have to always return false here.
-#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_CHROMEOS)
   DownloadCheckResultReason reason = REASON_MAX;
   ClientDownloadRequest::DownloadType type =
       ClientDownloadRequest::WIN_EXECUTABLE;
   return (CheckClientDownloadRequest::IsSupportedDownload(
               item, target_path, &reason, &type) &&
           (ClientDownloadRequest::CHROME_EXTENSION != type));
-#else
-  return false;
-#endif
 }
 
 DownloadProtectionService::ClientDownloadRequestSubscription
diff --git a/chrome/browser/safe_browsing/download_protection_service_unittest.cc b/chrome/browser/safe_browsing/download_protection_service_unittest.cc
index 3ec5c7b..e4116d0 100644
--- a/chrome/browser/safe_browsing/download_protection_service_unittest.cc
+++ b/chrome/browser/safe_browsing/download_protection_service_unittest.cc
@@ -488,13 +488,7 @@
                  base::Unretained(this)));
   MessageLoop::current()->Run();
 
-#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_CHROMEOS)
   const bool expect_request = is_extended_reporting && !is_incognito;
-#else
-  // For !(OS_WIN || OS_MACOSX || OS_CHROMEOS),
-  // no file types are currently supported.
-  const bool expect_request = false;
-#endif
 
   if (expect_request) {
     ASSERT_TRUE(HasClientDownloadRequest());
@@ -635,14 +629,9 @@
                  base::Unretained(this)));
   MessageLoop::current()->Run();
 
-#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_CHROMEOS)
   EXPECT_TRUE(IsResult(DownloadProtectionService::DANGEROUS));
   EXPECT_TRUE(HasClientDownloadRequest());
   ClearClientDownloadRequest();
-#else
-  EXPECT_TRUE(IsResult(DownloadProtectionService::UNKNOWN));
-  EXPECT_FALSE(HasClientDownloadRequest());
-#endif
 
   // Check that the referrer is not matched against the whitelist.
   referrer = GURL("http://www.google.com/");
@@ -652,14 +641,9 @@
                  base::Unretained(this)));
   MessageLoop::current()->Run();
 
-#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_CHROMEOS)
   EXPECT_TRUE(IsResult(DownloadProtectionService::DANGEROUS));
   EXPECT_TRUE(HasClientDownloadRequest());
   ClearClientDownloadRequest();
-#else
-  EXPECT_TRUE(IsResult(DownloadProtectionService::UNKNOWN));
-  EXPECT_FALSE(HasClientDownloadRequest());
-#endif
 
   // Redirect from a site shouldn't be checked either.
   url_chain.insert(url_chain.begin(), GURL("http://www.google.com/redirect"));
@@ -669,14 +653,9 @@
                  base::Unretained(this)));
   MessageLoop::current()->Run();
 
-#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_CHROMEOS)
   EXPECT_TRUE(IsResult(DownloadProtectionService::DANGEROUS));
   EXPECT_TRUE(HasClientDownloadRequest());
   ClearClientDownloadRequest();
-#else
-  EXPECT_TRUE(IsResult(DownloadProtectionService::UNKNOWN));
-  EXPECT_FALSE(HasClientDownloadRequest());
-#endif
 
   // Only if the final url is whitelisted should it be SAFE.
   url_chain.push_back(GURL("http://www.google.com/a.exe"));
@@ -781,17 +760,9 @@
                  base::Unretained(this)));
   MessageLoop::current()->Run();
 
-#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_CHROMEOS)
   EXPECT_TRUE(IsResult(DownloadProtectionService::SAFE));
   EXPECT_TRUE(HasClientDownloadRequest());
   ClearClientDownloadRequest();
-#else
-  // On !(OS_WIN || OS_MACOSX || OS_CHROMEOS),
-  // no file types are currently supported. Hence all
-  // requests to CheckClientDownload() result in a verdict of UNKNOWN.
-  EXPECT_TRUE(IsResult(DownloadProtectionService::UNKNOWN));
-  EXPECT_FALSE(HasClientDownloadRequest());
-#endif
 
   // Invalid response should result in UNKNOWN.
   response.Clear();
@@ -806,12 +777,8 @@
                  base::Unretained(this)));
   MessageLoop::current()->Run();
   EXPECT_TRUE(IsResult(DownloadProtectionService::UNKNOWN));
-#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_CHROMEOS)
   EXPECT_TRUE(HasClientDownloadRequest());
   ClearClientDownloadRequest();
-#else
-  EXPECT_FALSE(HasClientDownloadRequest());
-#endif
   std::string feedback_ping;
   std::string feedback_response;
   EXPECT_FALSE(DownloadFeedbackService::GetPingsForDownloadForTesting(
@@ -832,14 +799,9 @@
   EXPECT_FALSE(DownloadFeedbackService::GetPingsForDownloadForTesting(
       item, &feedback_ping, &feedback_response));
 
-#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_CHROMEOS)
   EXPECT_TRUE(IsResult(DownloadProtectionService::DANGEROUS));
   EXPECT_TRUE(HasClientDownloadRequest());
   ClearClientDownloadRequest();
-#else
-  EXPECT_TRUE(IsResult(DownloadProtectionService::UNKNOWN));
-  EXPECT_FALSE(HasClientDownloadRequest());
-#endif
 
   // If the response is uncommon the result should also be marked as uncommon.
   response.set_verdict(ClientDownloadResponse::UNCOMMON);
@@ -853,7 +815,6 @@
       base::Bind(&DownloadProtectionServiceTest::CheckDoneCallback,
                  base::Unretained(this)));
   MessageLoop::current()->Run();
-#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_CHROMEOS)
   EXPECT_TRUE(IsResult(DownloadProtectionService::UNCOMMON));
   EXPECT_TRUE(DownloadFeedbackService::GetPingsForDownloadForTesting(
       item, &feedback_ping, &feedback_response));
@@ -863,9 +824,6 @@
   EXPECT_EQ(response.SerializeAsString(), feedback_response);
   EXPECT_TRUE(HasClientDownloadRequest());
   ClearClientDownloadRequest();
-#else
-  EXPECT_TRUE(IsResult(DownloadProtectionService::UNKNOWN));
-#endif
 
   // If the response is dangerous_host the result should also be marked as
   // dangerous_host.
@@ -880,16 +838,12 @@
       base::Bind(&DownloadProtectionServiceTest::CheckDoneCallback,
                  base::Unretained(this)));
   MessageLoop::current()->Run();
-#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_CHROMEOS)
   EXPECT_TRUE(IsResult(DownloadProtectionService::DANGEROUS_HOST));
   EXPECT_TRUE(DownloadFeedbackService::GetPingsForDownloadForTesting(
       item, &feedback_ping, &feedback_response));
   EXPECT_EQ(response.SerializeAsString(), feedback_response);
   EXPECT_TRUE(HasClientDownloadRequest());
   ClearClientDownloadRequest();
-#else
-  EXPECT_TRUE(IsResult(DownloadProtectionService::UNKNOWN));
-#endif
 
   // If the response is POTENTIALLY_UNWANTED the result should also be marked as
   // POTENTIALLY_UNWANTED.
@@ -905,14 +859,9 @@
                  base::Unretained(this)));
   MessageLoop::current()->Run();
 
-#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_CHROMEOS)
   EXPECT_TRUE(IsResult(DownloadProtectionService::POTENTIALLY_UNWANTED));
   EXPECT_TRUE(HasClientDownloadRequest());
   ClearClientDownloadRequest();
-#else
-  EXPECT_TRUE(IsResult(DownloadProtectionService::UNKNOWN));
-  EXPECT_FALSE(HasClientDownloadRequest());
-#endif
 }
 
 TEST_F(DownloadProtectionServiceTest, CheckClientDownloadHTTPS) {
@@ -960,14 +909,9 @@
                  base::Unretained(this)));
   MessageLoop::current()->Run();
 
-#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_CHROMEOS)
   EXPECT_TRUE(IsResult(DownloadProtectionService::DANGEROUS));
   EXPECT_TRUE(HasClientDownloadRequest());
   ClearClientDownloadRequest();
-#else
-  EXPECT_TRUE(IsResult(DownloadProtectionService::UNKNOWN));
-  EXPECT_FALSE(HasClientDownloadRequest());
-#endif
 }
 
 TEST_F(DownloadProtectionServiceTest, CheckClientDownloadBlob) {
@@ -1014,14 +958,9 @@
                  base::Unretained(this)));
   MessageLoop::current()->Run();
 
-#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_CHROMEOS)
   EXPECT_TRUE(IsResult(DownloadProtectionService::DANGEROUS));
   EXPECT_TRUE(HasClientDownloadRequest());
   ClearClientDownloadRequest();
-#else
-  EXPECT_TRUE(IsResult(DownloadProtectionService::UNKNOWN));
-  EXPECT_FALSE(HasClientDownloadRequest());
-#endif
 }
 
 TEST_F(DownloadProtectionServiceTest, CheckClientDownloadData) {
@@ -1072,7 +1011,6 @@
                  base::Unretained(this)));
   MessageLoop::current()->Run();
 
-#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_CHROMEOS)
   EXPECT_TRUE(IsResult(DownloadProtectionService::DANGEROUS));
   ASSERT_TRUE(HasClientDownloadRequest());
   const ClientDownloadRequest& request = *GetClientDownloadRequest();
@@ -1099,10 +1037,6 @@
                                       ClientDownloadRequest::DOWNLOAD_URL,
                                       kExpectedUrl, kExpectedReferrer));
   ClearClientDownloadRequest();
-#else
-  EXPECT_TRUE(IsResult(DownloadProtectionService::UNKNOWN));
-  EXPECT_FALSE(HasClientDownloadRequest());
-#endif
 }
 
 TEST_F(DownloadProtectionServiceTest, CheckClientDownloadZip) {
@@ -1174,7 +1108,6 @@
                  base::Unretained(this)));
   MessageLoop::current()->Run();
 
-#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_CHROMEOS)
   EXPECT_TRUE(IsResult(DownloadProtectionService::SAFE));
   EXPECT_TRUE(HasClientDownloadRequest());
   const ClientDownloadRequest& request = *GetClientDownloadRequest();
@@ -1190,13 +1123,6 @@
   EXPECT_EQ(static_cast<int64_t>(file_contents.size()),
             archived_binary->length());
   ClearClientDownloadRequest();
-#else
-  // For !(OS_WIN || OS_MACOSX || OS_CHROMEOS),
-  // no file types are currently supported. Hence
-  // the resulting verdict is UNKNOWN.
-  EXPECT_TRUE(IsResult(DownloadProtectionService::UNKNOWN));
-  EXPECT_FALSE(HasClientDownloadRequest());
-#endif
   Mock::VerifyAndClearExpectations(binary_feature_extractor_.get());
 
   // If the response is dangerous the result should also be marked as
@@ -1213,14 +1139,9 @@
                  base::Unretained(this)));
   MessageLoop::current()->Run();
 
-#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_CHROMEOS)
   EXPECT_TRUE(IsResult(DownloadProtectionService::DANGEROUS));
   EXPECT_TRUE(HasClientDownloadRequest());
   ClearClientDownloadRequest();
-#else
-  EXPECT_TRUE(IsResult(DownloadProtectionService::UNKNOWN));
-  EXPECT_FALSE(HasClientDownloadRequest());
-#endif
   Mock::VerifyAndClearExpectations(binary_feature_extractor_.get());
 
   // Repeat the test with an archive inside the zip file in addition to the
@@ -1236,20 +1157,12 @@
                         base::Unretained(this)));
   MessageLoop::current()->Run();
 
-#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_CHROMEOS)
   ASSERT_TRUE(HasClientDownloadRequest());
   EXPECT_EQ(1, GetClientDownloadRequest()->archived_binary_size());
   EXPECT_TRUE(GetClientDownloadRequest()->has_download_type());
   EXPECT_EQ(ClientDownloadRequest_DownloadType_ZIPPED_EXECUTABLE,
             GetClientDownloadRequest()->download_type());
   ClearClientDownloadRequest();
-#else
-  // For !(OS_WIN || OS_MACOSX || OS_CHROMEOS),
-  // no file types are currently supported. Hence
-  // the resulting verdict is UNKNOWN.
-  EXPECT_TRUE(IsResult(DownloadProtectionService::UNKNOWN));
-  EXPECT_FALSE(HasClientDownloadRequest());
-#endif
   Mock::VerifyAndClearExpectations(binary_feature_extractor_.get());
 
   // Repeat the test with just the archive inside the zip file.
@@ -1262,20 +1175,12 @@
                         base::Unretained(this)));
   MessageLoop::current()->Run();
 
-#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_CHROMEOS)
   ASSERT_TRUE(HasClientDownloadRequest());
   EXPECT_EQ(0, GetClientDownloadRequest()->archived_binary_size());
   EXPECT_TRUE(GetClientDownloadRequest()->has_download_type());
   EXPECT_EQ(ClientDownloadRequest_DownloadType_ZIPPED_ARCHIVE,
             GetClientDownloadRequest()->download_type());
   ClearClientDownloadRequest();
-#else
-  // For !(OS_WIN || OS_MACOSX || OS_CHROMEOS),
-  // no file types are currently supported. Hence
-  // the resulting verdict is UNKNOWN.
-  EXPECT_TRUE(IsResult(DownloadProtectionService::UNKNOWN));
-  EXPECT_FALSE(HasClientDownloadRequest());
-#endif
   Mock::VerifyAndClearExpectations(binary_feature_extractor_.get());
 }
 
@@ -1389,13 +1294,6 @@
       base::Bind(&DownloadProtectionServiceTest::CheckDoneCallback,
                  base::Unretained(this)));
 
-#if !defined(OS_WIN) && !defined(OS_MACOSX) && !defined(OS_CHROMEOS)
-  // SendRequest is not called.  Wait for FinishRequest to call our callback.
-  MessageLoop::current()->Run();
-  net::TestURLFetcher* fetcher = factory.GetFetcherByID(0);
-  EXPECT_EQ(NULL, fetcher);
-  EXPECT_FALSE(HasClientDownloadRequest());
-#else
   // Run the message loop(s) until SendRequest is called.
   FlushThreadMessageLoops();
   EXPECT_TRUE(HasClientDownloadRequest());
@@ -1436,7 +1334,6 @@
       base::Bind(&DownloadProtectionServiceTest::SendURLFetchComplete,
                  base::Unretained(this), fetcher));
   MessageLoop::current()->Run();
-#endif
 }
 
 // Similar to above, but with an unsigned binary.
@@ -1479,13 +1376,6 @@
       base::Bind(&DownloadProtectionServiceTest::CheckDoneCallback,
                  base::Unretained(this)));
 
-#if !defined(OS_WIN) && !defined(OS_MACOSX) && !defined(OS_CHROMEOS)
-  // SendRequest is not called.  Wait for FinishRequest to call our callback.
-  MessageLoop::current()->Run();
-  net::TestURLFetcher* fetcher = factory.GetFetcherByID(0);
-  EXPECT_EQ(NULL, fetcher);
-  EXPECT_FALSE(HasClientDownloadRequest());
-#else
   // Run the message loop(s) until SendRequest is called.
   FlushThreadMessageLoops();
   EXPECT_TRUE(HasClientDownloadRequest());
@@ -1515,7 +1405,6 @@
       base::Bind(&DownloadProtectionServiceTest::SendURLFetchComplete,
                  base::Unretained(this), fetcher));
   MessageLoop::current()->Run();
-#endif
 }
 
 // Similar to above, but with tab history.
@@ -1566,13 +1455,6 @@
         base::Bind(&DownloadProtectionServiceTest::CheckDoneCallback,
                    base::Unretained(this)));
 
-#if !defined(OS_WIN) && !defined(OS_MACOSX) && !defined(OS_CHROMEOS)
-    // SendRequest is not called.  Wait for FinishRequest to call our callback.
-    MessageLoop::current()->Run();
-    net::TestURLFetcher* fetcher = factory.GetFetcherByID(0);
-    EXPECT_EQ(NULL, fetcher);
-    EXPECT_FALSE(HasClientDownloadRequest());
-#else
     EXPECT_EQ(0, fetcher_watcher.WaitForRequest());
     EXPECT_TRUE(HasClientDownloadRequest());
     ClearClientDownloadRequest();
@@ -1619,7 +1501,6 @@
                    base::Unretained(this),
                    fetcher));
     MessageLoop::current()->Run();
-#endif
   }
 
   // Now try with a history match.
@@ -1645,13 +1526,6 @@
         &item,
         base::Bind(&DownloadProtectionServiceTest::CheckDoneCallback,
                    base::Unretained(this)));
-#if !defined(OS_WIN) && !defined(OS_MACOSX) && !defined(OS_CHROMEOS)
-    // SendRequest is not called.  Wait for FinishRequest to call our callback.
-    MessageLoop::current()->Run();
-    net::TestURLFetcher* fetcher = factory.GetFetcherByID(0);
-    EXPECT_EQ(NULL, fetcher);
-    EXPECT_FALSE(HasClientDownloadRequest());
-#else
     EXPECT_EQ(0, fetcher_watcher.WaitForRequest());
     EXPECT_TRUE(HasClientDownloadRequest());
     ClearClientDownloadRequest();
@@ -1700,7 +1574,6 @@
                    base::Unretained(this),
                    fetcher));
     MessageLoop::current()->Run();
-#endif
   }
 }
 
@@ -1811,12 +1684,8 @@
   // anything yet.
   MessageLoop::current()->Run();
   EXPECT_TRUE(IsResult(DownloadProtectionService::UNKNOWN));
-#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_CHROMEOS)
   EXPECT_TRUE(HasClientDownloadRequest());
   ClearClientDownloadRequest();
-#else
-  EXPECT_FALSE(HasClientDownloadRequest());
-#endif
 }
 
 TEST_F(DownloadProtectionServiceTest, TestDownloadItemDestroyed) {
@@ -2092,15 +1961,8 @@
   MessageLoop::current()->Run();
 
   EXPECT_FALSE(HasClientDownloadRequest());
-#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_CHROMEOS)
   // Overriden by flag:
   EXPECT_TRUE(IsResult(DownloadProtectionService::DANGEROUS));
-#else
-  // On !(OS_WIN || OS_MACOSX || OS_CHROMEOS),
-  // no file types are currently supported. Hence all
-  // requests to CheckClientDownload() result in a verdict of UNKNOWN.
-  EXPECT_TRUE(IsResult(DownloadProtectionService::UNKNOWN));
-#endif
 }
 
 // Test a real .zip with a real .exe in it, where the .exe is manually
@@ -2139,15 +2001,8 @@
   MessageLoop::current()->Run();
 
   EXPECT_FALSE(HasClientDownloadRequest());
-#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_CHROMEOS)
   // Overriden by flag:
   EXPECT_TRUE(IsResult(DownloadProtectionService::DANGEROUS));
-#else
-  // On !(OS_WIN || OS_MACOSX || OS_CHROMEOS),
-  // no file types are currently supported. Hence all
-  // requests to CheckClientDownload() result in a verdict of UNKNOWN.
-  EXPECT_TRUE(IsResult(DownloadProtectionService::UNKNOWN));
-#endif
 }
 
 }  // namespace safe_browsing
diff --git a/chrome/browser/safe_browsing/remote_database_manager.cc b/chrome/browser/safe_browsing/remote_database_manager.cc
index b834b856..9eb0d7e 100644
--- a/chrome/browser/safe_browsing/remote_database_manager.cc
+++ b/chrome/browser/safe_browsing/remote_database_manager.cc
@@ -18,10 +18,8 @@
 
 namespace {
 
-// Android field trial
+// Android field trial for controlling types_to_check.
 const char kAndroidFieldExperiment[] = "SafeBrowsingAndroid";
-const char kAndroidFieldParam[] = "enabled";
-const char kAndroidFieldParamEnabledValue[] = "true";
 const char kAndroidTypesToCheckParam[] = "types_to_check";
 
 }  // namespace
@@ -94,27 +92,41 @@
 // TODO(nparker): Add more tests for this class
 RemoteSafeBrowsingDatabaseManager::RemoteSafeBrowsingDatabaseManager()
     : enabled_(false) {
-
-  // Check if the field trial is enabled.
-  const std::string enabled_param = variations::GetVariationParamValue(
-      kAndroidFieldExperiment, kAndroidFieldParam);
-  is_android_field_trial_enabled_ =
-      (enabled_param == kAndroidFieldParamEnabledValue);
-
   // Decide which resource types to check. These two are the minimum.
   resource_types_to_check_.insert(content::RESOURCE_TYPE_MAIN_FRAME);
   resource_types_to_check_.insert(content::RESOURCE_TYPE_SUB_FRAME);
 
   // The param is expected to be a comma-separated list of ints
-  // corresponding to the enum types.
+  // corresponding to the enum types.  We're keeping this finch
+  // control around so we can add back types if they later become dangerous.
   const std::string ints_str = variations::GetVariationParamValue(
       kAndroidFieldExperiment, kAndroidTypesToCheckParam);
-  for (const std::string& val_str : base::SplitString(
-           ints_str, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL)) {
-    int i;
-    if (base::StringToInt(val_str, &i) && i >= 0 &&
-        i < content::RESOURCE_TYPE_LAST_TYPE) {
-      resource_types_to_check_.insert(static_cast<content::ResourceType>(i));
+  if (ints_str.empty()) {
+    // By default, we check all types except a few.
+    static_assert(content::RESOURCE_TYPE_LAST_TYPE ==
+                      content::RESOURCE_TYPE_SERVICE_WORKER + 1,
+                  "Decide if new resource type should be skipped on mobile.");
+    for (int t_int = 0; t_int < content::RESOURCE_TYPE_LAST_TYPE; t_int++) {
+      content::ResourceType t = static_cast<content::ResourceType>(t_int);
+      switch (t) {
+        case content::RESOURCE_TYPE_STYLESHEET:
+        case content::RESOURCE_TYPE_IMAGE:
+        case content::RESOURCE_TYPE_FONT_RESOURCE:
+        case content::RESOURCE_TYPE_FAVICON:
+          break;
+        default:
+          resource_types_to_check_.insert(t);
+      }
+    }
+  } else {
+    // Use the finch param.
+    for (const std::string& val_str : base::SplitString(
+             ints_str, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL)) {
+      int i;
+      if (base::StringToInt(val_str, &i) && i >= 0 &&
+          i < content::RESOURCE_TYPE_LAST_TYPE) {
+        resource_types_to_check_.insert(static_cast<content::ResourceType>(i));
+      }
     }
   }
 }
@@ -124,8 +136,7 @@
 }
 
 bool RemoteSafeBrowsingDatabaseManager::IsSupported() const {
-  return SafeBrowsingApiHandler::GetInstance() != nullptr &&
-         is_android_field_trial_enabled_;
+  return SafeBrowsingApiHandler::GetInstance() != nullptr;
 }
 
 safe_browsing::ThreatSource RemoteSafeBrowsingDatabaseManager::GetThreatSource()
diff --git a/chrome/browser/safe_browsing/remote_database_manager.h b/chrome/browser/safe_browsing/remote_database_manager.h
index b630a8a..c3c5de8 100644
--- a/chrome/browser/safe_browsing/remote_database_manager.h
+++ b/chrome/browser/safe_browsing/remote_database_manager.h
@@ -69,7 +69,6 @@
   bool enabled_;
 
   std::set<content::ResourceType> resource_types_to_check_;
-  bool is_android_field_trial_enabled_;
 
   friend class base::RefCountedThreadSafe<RemoteSafeBrowsingDatabaseManager>;
   DISALLOW_COPY_AND_ASSIGN(RemoteSafeBrowsingDatabaseManager);
diff --git a/chrome/browser/safe_browsing/remote_database_manager_unittest.cc b/chrome/browser/safe_browsing/remote_database_manager_unittest.cc
index 0726720..e584118 100644
--- a/chrome/browser/safe_browsing/remote_database_manager_unittest.cc
+++ b/chrome/browser/safe_browsing/remote_database_manager_unittest.cc
@@ -35,8 +35,7 @@
   }
 
   // Setup the two field trial params.  These are read in db_'s ctor.
-  void SetFieldTrialParams(const std::string enabled_val,
-                           const std::string types_to_check_val) {
+  void SetFieldTrialParams(const std::string types_to_check_val) {
     // Destroy the existing FieldTrialList before creating a new one to avoid
     // a DCHECK.
     field_trials_.reset();
@@ -50,8 +49,6 @@
         base::FieldTrialList::CreateFieldTrial(experiment_name, group_name));
 
     std::map<std::string, std::string> params;
-    if (!enabled_val.empty())
-      params["enabled"] = enabled_val;
     if (!types_to_check_val.empty())
       params["types_to_check"] = types_to_check_val;
 
@@ -64,11 +61,7 @@
   scoped_refptr<RemoteSafeBrowsingDatabaseManager> db_;
 };
 
-TEST_F(RemoteDatabaseManagerTest, DisabledViaNullOrTrial) {
-  EXPECT_FALSE(db_->IsSupported());
-
-  SetFieldTrialParams("true", "");
-  db_ = new RemoteSafeBrowsingDatabaseManager();
+TEST_F(RemoteDatabaseManagerTest, DisabledViaNull) {
   EXPECT_TRUE(db_->IsSupported());
 
   SafeBrowsingApiHandler::SetInstance(nullptr);
@@ -76,17 +69,25 @@
 }
 
 TEST_F(RemoteDatabaseManagerTest, TypesToCheckDefault) {
-  EXPECT_TRUE(db_->CanCheckResourceType(content::RESOURCE_TYPE_MAIN_FRAME));
-  EXPECT_TRUE(db_->CanCheckResourceType(content::RESOURCE_TYPE_SUB_FRAME));
-  // The rest are false.
-  for (int t = content::RESOURCE_TYPE_SUB_FRAME + 1;
-       t < content::RESOURCE_TYPE_LAST_TYPE; t++) {
-    EXPECT_FALSE(
-        db_->CanCheckResourceType(static_cast<content::ResourceType>(t)));
+  // Most are true, a few are false.
+  for (int t_int = 0; t_int < content::RESOURCE_TYPE_LAST_TYPE; t_int++) {
+    content::ResourceType t = static_cast<content::ResourceType>(t_int);
+    switch (t) {
+      case content::RESOURCE_TYPE_STYLESHEET:
+      case content::RESOURCE_TYPE_IMAGE:
+      case content::RESOURCE_TYPE_FONT_RESOURCE:
+      case content::RESOURCE_TYPE_FAVICON:
+        EXPECT_FALSE(db_->CanCheckResourceType(t));
+        break;
+      default:
+        EXPECT_TRUE(db_->CanCheckResourceType(t));
+        break;
+    }
   }
 }
+
 TEST_F(RemoteDatabaseManagerTest, TypesToCheckFromTrial) {
-  SetFieldTrialParams("true", "1,2,blah, 9");
+  SetFieldTrialParams("1,2,blah, 9");
   db_ = new RemoteSafeBrowsingDatabaseManager();
   EXPECT_TRUE(db_->CanCheckResourceType(
       content::RESOURCE_TYPE_MAIN_FRAME));  // defaulted
diff --git a/chrome/browser/safe_browsing/safe_browsing_blocking_page.cc b/chrome/browser/safe_browsing/safe_browsing_blocking_page.cc
index 5ebc8d3..e4f71f16 100644
--- a/chrome/browser/safe_browsing/safe_browsing_blocking_page.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_blocking_page.cc
@@ -514,15 +514,10 @@
 // static
 bool SafeBrowsingBlockingPage::IsMainPageLoadBlocked(
     const UnsafeResourceList& unsafe_resources) {
-  // Client-side phishing detection interstitials never block the main frame
-  // load, since they happen after the page is finished loading.
-  if (unsafe_resources[0].threat_type ==
-      SB_THREAT_TYPE_CLIENT_SIDE_PHISHING_URL) {
-    return false;
-  }
-
-  // Otherwise, check the threat type.
-  return unsafe_resources.size() == 1 && !unsafe_resources[0].is_subresource;
+  // If there is more than one unsafe resource, the main page load must not be
+  // blocked. Otherwise, check if the one resource is.
+  return unsafe_resources.size() == 1 &&
+         unsafe_resources[0].IsMainPageLoadBlocked();
 }
 
 std::string SafeBrowsingBlockingPage::GetMetricPrefix() const {
diff --git a/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc b/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc
index e88dfe1b..9ec2fca 100644
--- a/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc
@@ -6,6 +6,8 @@
 // threat urls.  It then uses a real browser to go to these urls, and sends
 // "goback" or "proceed" commands and verifies they work.
 
+#include <algorithm>
+
 #include "base/bind.h"
 #include "base/command_line.h"
 #include "base/prefs/pref_service.h"
@@ -59,6 +61,7 @@
 
 const char kEmptyPage[] = "empty.html";
 const char kMalwarePage[] = "safe_browsing/malware.html";
+const char kMalwarePage2[] = "safe_browsing/malware2.html";
 const char kMalwareIframe[] = "safe_browsing/malware_iframe.html";
 const char kUnrelatedUrl[] = "https://www.google.com";
 
@@ -420,7 +423,7 @@
   // navigates to a page with an iframe containing the threat site, and returns
   // the url of the parent page.
   GURL SetupThreatIframeWarningAndNavigate() {
-    GURL url = net::URLRequestMockHTTPJob::GetMockUrl(kMalwarePage);
+    GURL url = net::URLRequestMockHTTPJob::GetMockUrl(kMalwarePage2);
     GURL iframe_url = net::URLRequestMockHTTPJob::GetMockUrl(kMalwareIframe);
     SetURLThreatType(iframe_url, GetParam());
 
@@ -448,24 +451,6 @@
     interstitial_page->CommandReceived(base::IntToString(command));
   }
 
-  void DontProceedThroughInterstitial() {
-    WebContents* contents =
-        browser()->tab_strip_model()->GetActiveWebContents();
-    InterstitialPage* interstitial_page = InterstitialPage::GetInterstitialPage(
-        contents);
-    ASSERT_TRUE(interstitial_page);
-    interstitial_page->DontProceed();
-  }
-
-  void ProceedThroughInterstitial() {
-    WebContents* contents =
-        browser()->tab_strip_model()->GetActiveWebContents();
-    InterstitialPage* interstitial_page = InterstitialPage::GetInterstitialPage(
-        contents);
-    ASSERT_TRUE(interstitial_page);
-    interstitial_page->Proceed();
-  }
-
   void AssertNoInterstitial(bool wait_for_delete) {
     WebContents* contents =
         browser()->tab_strip_model()->GetActiveWebContents();
@@ -756,6 +741,120 @@
     ASSERT_TRUE(report.ParseFromString(serialized));
     // Verify the report is complete.
     EXPECT_TRUE(report.complete());
+    // Do some basic verification of report contents.
+    EXPECT_EQ(url.spec(), report.page_url());
+    EXPECT_EQ(net::URLRequestMockHTTPJob::GetMockUrl(kMalwareIframe).spec(),
+              report.url());
+    std::vector<std::string> report_urls;
+    for (int i = 0; i < report.resources_size(); ++i)
+      report_urls.push_back(report.resources(i).url());
+    ASSERT_EQ(3U, report_urls.size());
+    std::sort(report_urls.begin(), report_urls.end());
+    EXPECT_EQ("http://example.com/cross_site_iframe.html", report_urls[0]);
+    EXPECT_EQ(url.spec(), report_urls[1]);
+    EXPECT_EQ(net::URLRequestMockHTTPJob::GetMockUrl(kMalwareIframe).spec(),
+              report_urls[2]);
+  }
+}
+
+IN_PROC_BROWSER_TEST_P(SafeBrowsingBlockingPageBrowserTest,
+                       MainFrameBlockedShouldHaveNoDOMDetailsWhenDontProceed) {
+  const bool expect_threat_details =
+      SafeBrowsingBlockingPage::ShouldReportThreatDetails(GetParam());
+
+  scoped_refptr<content::MessageLoopRunner> threat_report_sent_runner(
+      new content::MessageLoopRunner);
+  if (expect_threat_details)
+    SetReportSentCallback(threat_report_sent_runner->QuitClosure());
+
+  // Navigate to a safe page which contains multiple potential DOM details.
+  // (Despite the name, kMalwarePage is not the page flagged as malware in this
+  // test.)
+  GURL safe_url(net::URLRequestMockHTTPJob::GetMockUrl(kMalwarePage));
+  ui_test_utils::NavigateToURL(browser(), safe_url);
+
+  EXPECT_EQ(nullptr, details_factory_.get_details());
+
+  // Start navigation to bad page (kEmptyPage), which will be blocked before it
+  // is committed.
+  GURL url = SetupWarningAndNavigate();
+
+  FakeThreatDetails* fake_threat_details = details_factory_.get_details();
+  EXPECT_EQ(expect_threat_details, fake_threat_details != nullptr);
+
+  // Go back.
+  EXPECT_EQ(VISIBLE, GetVisibility("extended-reporting-opt-in"));
+  EXPECT_TRUE(Click("opt-in-checkbox"));
+  EXPECT_TRUE(ClickAndWaitForDetach("primary-button"));
+  AssertNoInterstitial(true);  // Assert the interstitial is gone
+
+  EXPECT_TRUE(browser()->profile()->GetPrefs()->GetBoolean(
+              prefs::kSafeBrowsingExtendedReportingEnabled));
+  EXPECT_EQ(safe_url,
+            browser()->tab_strip_model()->GetActiveWebContents()->GetURL());
+
+  if (expect_threat_details) {
+    threat_report_sent_runner->Run();
+    std::string serialized = GetReportSent();
+    ClientSafeBrowsingReportRequest report;
+    ASSERT_TRUE(report.ParseFromString(serialized));
+    // Verify the report is complete.
+    EXPECT_TRUE(report.complete());
+    EXPECT_EQ(url.spec(), report.page_url());
+    EXPECT_EQ(url.spec(), report.url());
+    ASSERT_EQ(1, report.resources_size());
+    EXPECT_EQ(url.spec(), report.resources(0).url());
+  }
+}
+
+IN_PROC_BROWSER_TEST_P(
+    SafeBrowsingBlockingPageBrowserTest,
+    MainFrameBlockedShouldHaveNoDOMDetailsWhenProceeding) {
+  const bool expect_threat_details =
+      SafeBrowsingBlockingPage::ShouldReportThreatDetails(GetParam());
+
+  scoped_refptr<content::MessageLoopRunner> threat_report_sent_runner(
+      new content::MessageLoopRunner);
+  if (expect_threat_details)
+    SetReportSentCallback(threat_report_sent_runner->QuitClosure());
+
+  // Navigate to a safe page which contains multiple potential DOM details.
+  // (Despite the name, kMalwarePage is not the page flagged as malware in this
+  // test.)
+  ui_test_utils::NavigateToURL(
+      browser(), net::URLRequestMockHTTPJob::GetMockUrl(kMalwarePage));
+
+  EXPECT_EQ(nullptr, details_factory_.get_details());
+
+  // Start navigation to bad page (kEmptyPage), which will be blocked before it
+  // is committed.
+  GURL url = SetupWarningAndNavigate();
+
+  FakeThreatDetails* fake_threat_details = details_factory_.get_details();
+  EXPECT_EQ(expect_threat_details, fake_threat_details != nullptr);
+
+  // Proceed through the warning.
+  EXPECT_EQ(VISIBLE, GetVisibility("extended-reporting-opt-in"));
+  EXPECT_TRUE(Click("opt-in-checkbox"));
+  EXPECT_TRUE(ClickAndWaitForDetach("proceed-link"));
+  AssertNoInterstitial(true);  // Assert the interstitial is gone
+
+  EXPECT_TRUE(browser()->profile()->GetPrefs()->GetBoolean(
+              prefs::kSafeBrowsingExtendedReportingEnabled));
+  EXPECT_EQ(url,
+            browser()->tab_strip_model()->GetActiveWebContents()->GetURL());
+
+  if (expect_threat_details) {
+    threat_report_sent_runner->Run();
+    std::string serialized = GetReportSent();
+    ClientSafeBrowsingReportRequest report;
+    ASSERT_TRUE(report.ParseFromString(serialized));
+    // Verify the report is complete.
+    EXPECT_TRUE(report.complete());
+    EXPECT_EQ(url.spec(), report.page_url());
+    EXPECT_EQ(url.spec(), report.url());
+    ASSERT_EQ(1, report.resources_size());
+    EXPECT_EQ(url.spec(), report.resources(0).url());
   }
 }
 
diff --git a/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc b/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc
index 72c6f77..91547a2 100644
--- a/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc
@@ -366,8 +366,6 @@
   virtual ~MockObserver() {}
   MOCK_METHOD1(OnSafeBrowsingHit,
                void(const SafeBrowsingUIManager::UnsafeResource&));
-  MOCK_METHOD1(OnSafeBrowsingMatch,
-               void(const SafeBrowsingUIManager::UnsafeResource&));
 };
 
 MATCHER_P(IsUnsafeResourceFor, url, "") {
@@ -631,8 +629,6 @@
   // we should see the interstitial page.
   SBFullHashResult malware_full_hash;
   GenUrlFullhashResultWithMetadata(url, &malware_full_hash);
-  EXPECT_CALL(observer_,
-              OnSafeBrowsingMatch(IsUnsafeResourceFor(url))).Times(1);
   EXPECT_CALL(observer_, OnSafeBrowsingHit(IsUnsafeResourceFor(url))).Times(1);
   SetupResponseForUrl(url, malware_full_hash);
   ui_test_utils::NavigateToURL(browser(), url);
@@ -648,8 +644,6 @@
   SBFullHashResult malware_full_hash;
   GenUrlFullhashResultWithMetadata(iframe_url, &malware_full_hash);
   EXPECT_CALL(observer_,
-              OnSafeBrowsingMatch(IsUnsafeResourceFor(iframe_url))).Times(1);
-  EXPECT_CALL(observer_,
               OnSafeBrowsingHit(IsUnsafeResourceFor(iframe_url))).Times(1);
   SetupResponseForUrl(iframe_url, malware_full_hash);
   ui_test_utils::NavigateToURL(browser(), main_url);
@@ -667,8 +661,6 @@
   switch (GetParam()) {
     case METADATA_NONE:  // Falls through.
     case METADATA_DISTRIBUTION:
-      EXPECT_CALL(observer_, OnSafeBrowsingMatch(IsUnsafeResourceFor(img_url)))
-          .Times(1);
       EXPECT_CALL(observer_, OnSafeBrowsingHit(IsUnsafeResourceFor(img_url)))
           .Times(1);
       break;
@@ -719,8 +711,6 @@
   // we should see the interstitial page.
   SBFullHashResult malware_full_hash;
   GenUrlFullhashResult(url, MALWARE, &malware_full_hash);
-  EXPECT_CALL(observer_,
-              OnSafeBrowsingMatch(IsUnsafeResourceFor(url))).Times(1);
   EXPECT_CALL(observer_, OnSafeBrowsingHit(IsUnsafeResourceFor(url)))
       .Times(1)
       .WillOnce(testing::Invoke(
@@ -733,10 +723,7 @@
   EXPECT_FALSE(ShowingInterstitialPage());
   Mock::VerifyAndClearExpectations(&observer_);
 
-  // Navigate back to kEmptyPage -- should hit the whitelist, and send a match
-  // call, but no hit call.
-  EXPECT_CALL(observer_,
-              OnSafeBrowsingMatch(IsUnsafeResourceFor(url))).Times(1);
+  // Navigate back to kEmptyPage -- should hit the whitelist.
   EXPECT_CALL(observer_, OnSafeBrowsingHit(IsUnsafeResourceFor(url))).Times(0);
   ui_test_utils::NavigateToURL(browser(), url);
   EXPECT_FALSE(ShowingInterstitialPage());
@@ -781,8 +768,6 @@
 
   // However, when we navigate to the malware page, we should still get
   // the interstitial.
-  EXPECT_CALL(observer_, OnSafeBrowsingMatch(IsUnsafeResourceFor(malware_url)))
-      .Times(1);
   EXPECT_CALL(observer_, OnSafeBrowsingHit(IsUnsafeResourceFor(malware_url)))
       .Times(1);
   ui_test_utils::NavigateToURL(browser(), malware_url);
diff --git a/chrome/browser/safe_browsing/safe_browsing_tab_observer.cc b/chrome/browser/safe_browsing/safe_browsing_tab_observer.cc
index 00df92e..7fe047c 100644
--- a/chrome/browser/safe_browsing/safe_browsing_tab_observer.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_tab_observer.cc
@@ -81,13 +81,4 @@
 #endif
 }
 
-bool SafeBrowsingTabObserver::DidPageReceiveSafeBrowsingMatch() const {
-#if defined(SAFE_BROWSING_CSD)
-  return safebrowsing_detection_host_ &&
-      safebrowsing_detection_host_->DidPageReceiveSafeBrowsingMatch();
-#else
-  return false;
-#endif
-}
-
 }  // namespace safe_browsing
diff --git a/chrome/browser/safe_browsing/safe_browsing_tab_observer.h b/chrome/browser/safe_browsing/safe_browsing_tab_observer.h
index 8047189..d32a02ac 100644
--- a/chrome/browser/safe_browsing/safe_browsing_tab_observer.h
+++ b/chrome/browser/safe_browsing/safe_browsing_tab_observer.h
@@ -23,9 +23,6 @@
  public:
   ~SafeBrowsingTabObserver() override;
 
-  // Forward to detection host, if safe-browsing is enabled.
-  bool DidPageReceiveSafeBrowsingMatch() const;
-
  private:
   explicit SafeBrowsingTabObserver(content::WebContents* web_contents);
   friend class content::WebContentsUserData<SafeBrowsingTabObserver>;
diff --git a/chrome/browser/safe_browsing/threat_details.cc b/chrome/browser/safe_browsing/threat_details.cc
index aa361e3..af89c5c 100644
--- a/chrome/browser/safe_browsing/threat_details.cc
+++ b/chrome/browser/safe_browsing/threat_details.cc
@@ -227,10 +227,14 @@
   if (nav_entry && !referrer_url.is_empty())
     AddUrl(referrer_url, GURL(), std::string(), NULL);
 
-  // Get URLs of frames, scripts etc from the DOM.
-  // OnReceivedThreatDOMDetails will be called when the renderer replies.
-  content::RenderViewHost* view = web_contents()->GetRenderViewHost();
-  view->Send(new SafeBrowsingMsg_GetThreatDOMDetails(view->GetRoutingID()));
+  if (!resource_.IsMainPageLoadBlocked()) {
+    // Get URLs of frames, scripts etc from the DOM.
+    // OnReceivedThreatDOMDetails will be called when the renderer replies.
+    // TODO(mattm): In theory, if the user proceeds through the warning DOM
+    // detail collection could be started once the page loads.
+    content::RenderViewHost* view = web_contents()->GetRenderViewHost();
+    view->Send(new SafeBrowsingMsg_GetThreatDOMDetails(view->GetRoutingID()));
+  }
 }
 
 // When the renderer is done, this is called.
diff --git a/chrome/browser/safe_browsing/ui_manager.cc b/chrome/browser/safe_browsing/ui_manager.cc
index ac8fb0d3..c6bb6d0 100644
--- a/chrome/browser/safe_browsing/ui_manager.cc
+++ b/chrome/browser/safe_browsing/ui_manager.cc
@@ -73,6 +73,21 @@
 
 SafeBrowsingUIManager::UnsafeResource::~UnsafeResource() { }
 
+bool SafeBrowsingUIManager::UnsafeResource::IsMainPageLoadBlocked() const {
+  // Subresource hits cannot happen until after main page load is committed.
+  if (is_subresource)
+    return false;
+
+  // Client-side phishing detection interstitials never block the main frame
+  // load, since they happen after the page is finished loading.
+  if (threat_type == SB_THREAT_TYPE_CLIENT_SIDE_PHISHING_URL ||
+      threat_type == SB_THREAT_TYPE_CLIENT_SIDE_MALWARE_URL) {
+    return false;
+  }
+
+  return true;
+}
+
 // SafeBrowsingUIManager -------------------------------------------------------
 
 SafeBrowsingUIManager::SafeBrowsingUIManager(
@@ -133,12 +148,6 @@
     }
   }
 
-  // Indicate to interested observers that the resource in question matched the
-  // SB filters.
-  if (resource.threat_type != SB_THREAT_TYPE_SAFE) {
-    FOR_EACH_OBSERVER(Observer, observer_list_, OnSafeBrowsingMatch(resource));
-  }
-
   // The tab might have been closed. If it was closed, just act as if "Don't
   // Proceed" had been chosen.
   WebContents* web_contents =
diff --git a/chrome/browser/safe_browsing/ui_manager.h b/chrome/browser/safe_browsing/ui_manager.h
index 74d6e2d9..191dccc 100644
--- a/chrome/browser/safe_browsing/ui_manager.h
+++ b/chrome/browser/safe_browsing/ui_manager.h
@@ -47,6 +47,8 @@
     UnsafeResource();
     ~UnsafeResource();
 
+    bool IsMainPageLoadBlocked() const;
+
     GURL url;
     GURL original_url;
     std::vector<GURL> redirect_urls;
@@ -65,13 +67,6 @@
   // was found.
   class Observer {
    public:
-    // The |resource| was classified as unsafe by SafeBrowsing.
-    // This method will be called every time an unsafe resource is
-    // loaded, even if it has already been whitelisted by the user.
-    // The |resource| must not be accessed after OnSafeBrowsingHit returns.
-    // This method will be called on the UI thread.
-    virtual void OnSafeBrowsingMatch(const UnsafeResource& resource) = 0;
-
     // The |resource| was classified as unsafe by SafeBrowsing, and is
     // not whitelisted.
     // The |resource| must not be accessed after OnSafeBrowsingHit returns.
diff --git a/chrome/browser/search_engines/template_url_service_factory.cc b/chrome/browser/search_engines/template_url_service_factory.cc
index f67a212..228b323 100644
--- a/chrome/browser/search_engines/template_url_service_factory.cc
+++ b/chrome/browser/search_engines/template_url_service_factory.cc
@@ -22,6 +22,10 @@
 #include "components/search_engines/search_engines_pref_names.h"
 #include "components/search_engines/template_url_service.h"
 
+#if defined(OS_WIN)
+#include "components/search_engines/desktop_search_win.h"
+#endif  // defined(OS_WIN)
+
 #if defined(ENABLE_RLZ)
 #include "components/rlz/rlz_tracker.h"
 #endif
@@ -79,6 +83,9 @@
     user_prefs::PrefRegistrySyncable* registry) {
   DefaultSearchManager::RegisterProfilePrefs(registry);
   TemplateURLService::RegisterProfilePrefs(registry);
+#if defined(OS_WIN)
+  RegisterWindowsDesktopSearchRedirectionPref(registry);
+#endif
 }
 
 content::BrowserContext* TemplateURLServiceFactory::GetBrowserContextToUse(
diff --git a/chrome/browser/signin/chrome_signin_helper.cc b/chrome/browser/signin/chrome_signin_helper.cc
index 0179bf3..4914aef 100644
--- a/chrome/browser/signin/chrome_signin_helper.cc
+++ b/chrome/browser/signin/chrome_signin_helper.cc
@@ -11,6 +11,7 @@
 #include "chrome/browser/signin/chrome_signin_client.h"
 #include "chrome/browser/tab_contents/tab_util.h"
 #include "chrome/browser/ui/browser_window.h"
+#include "chrome/common/features.h"
 #include "chrome/common/url_constants.h"
 #include "components/signin/core/browser/account_reconcilor.h"
 #include "components/signin/core/browser/signin_header_helper.h"
@@ -20,13 +21,13 @@
 #include "google_apis/gaia/gaia_auth_util.h"
 #include "net/url_request/url_request.h"
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
 #include "chrome/browser/android/signin/account_management_screen_helper.h"
 #else
 #include "chrome/browser/ui/browser_commands.h"
 #include "chrome/browser/ui/browser_finder.h"
 #include "extensions/browser/guest_view/web_view/web_view_renderer_state.h"
-#endif  // defined(OS_ANDROID)
+#endif  // BUILDFLAG(ANDROID_JAVA_UI)
 
 namespace signin {
 
@@ -54,7 +55,7 @@
       AccountReconcilorFactory::GetForProfile(profile);
   account_reconcilor->OnReceivedManageAccountsResponse(
       manage_accounts_params.service_type);
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(ANDROID_JAVA_UI)
   Browser* browser = chrome::FindBrowserWithWebContents(web_contents);
   if (browser) {
     BrowserWindow::AvatarBubbleMode bubble_mode;
@@ -76,7 +77,7 @@
     browser->window()->ShowAvatarBubbleFromAvatarButton(bubble_mode,
                                                         manage_accounts_params);
   }
-#else   // defined(OS_ANDROID)
+#else   // BUILDFLAG(ANDROID_JAVA_UI)
   if (service_type == signin::GAIA_SERVICE_TYPE_INCOGNITO) {
     GURL url(manage_accounts_params.continue_url.empty()
                  ? chrome::kChromeUINativeNewTabURL
@@ -90,7 +91,7 @@
     AccountManagementScreenHelper::OpenAccountManagementScreen(profile,
                                                                service_type);
   }
-#endif  // !defined(OS_ANDROID)
+#endif  // !BUILDFLAG(ANDROID_JAVA_UI)
 }
 
 // Returns the parameters contained in the X-Chrome-Manage-Accounts response
diff --git a/chrome/browser/signin/profile_oauth2_token_service_factory.cc b/chrome/browser/signin/profile_oauth2_token_service_factory.cc
index a8b65af..41e074f 100644
--- a/chrome/browser/signin/profile_oauth2_token_service_factory.cc
+++ b/chrome/browser/signin/profile_oauth2_token_service_factory.cc
@@ -9,10 +9,11 @@
 #include "chrome/browser/signin/chrome_signin_client_factory.h"
 #include "chrome/browser/signin/signin_error_controller_factory.h"
 #include "chrome/browser/web_data_service_factory.h"
+#include "chrome/common/features.h"
 #include "components/keyed_service/content/browser_context_dependency_manager.h"
 #include "components/signin/core/browser/profile_oauth2_token_service.h"
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
 #include "chrome/browser/signin/oauth2_token_service_delegate_android.h"
 #else
 #include "chrome/browser/signin/mutable_profile_oauth2_token_service_delegate.h"
@@ -50,7 +51,7 @@
 KeyedService* ProfileOAuth2TokenServiceFactory::BuildServiceInstanceFor(
     content::BrowserContext* context) const {
   Profile* profile = static_cast<Profile*>(context);
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
   OAuth2TokenServiceDelegateAndroid* delegate =
       new OAuth2TokenServiceDelegateAndroid(
           AccountTrackerServiceFactory::GetInstance()->GetForProfile(profile));
diff --git a/chrome/browser/site_details.cc b/chrome/browser/site_details.cc
index 4a4f3ae..4a326a83 100644
--- a/chrome/browser/site_details.cc
+++ b/chrome/browser/site_details.cc
@@ -8,6 +8,7 @@
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_process_host.h"
+#include "url/origin.h"
 
 #if defined(ENABLE_EXTENSIONS)
 #include "extensions/browser/extension_registry.h"
@@ -65,18 +66,15 @@
                         RenderFrameHost* frame) {
   BrowserContext* context = primary->GetBrowserContext();
 
-  GURL url = frame->GetLastCommittedURL();
+  // Determine the site from the frame's origin, with a fallback to the
+  // frame's URL.  In cases like <iframe sandbox>, we can wind up with an http
+  // URL but a unique origin.  The origin of the resource will still determine
+  // process placement.
+  url::Origin origin = frame->GetLastCommittedOrigin();
+  GURL site = SiteInstance::GetSiteForURL(
+      context, origin.unique() ? frame->GetLastCommittedURL()
+                               : GURL(origin.Serialize()));
 
-  // Treat about:blank url specially: use the URL on the SiteInstance if it is
-  // assigned. The rest of this computation must not depend on the
-  // SiteInstance's URL, since its value reflects the current process model, and
-  // this computation is simulating other process models.
-  if (url == GURL(url::kAboutBlankURL) &&
-      !frame->GetSiteInstance()->GetSiteURL().is_empty()) {
-    url = frame->GetSiteInstance()->GetSiteURL();
-  }
-
-  GURL site = SiteInstance::GetSiteForURL(context, url);
   bool should_isolate = ShouldIsolate(context, scenario, site);
 
   // Treat a subframe as part of its parent site if neither needs isolation.
diff --git a/chrome/browser/site_details_browsertest.cc b/chrome/browser/site_details_browsertest.cc
index 8686a4e..bc202c654 100644
--- a/chrome/browser/site_details_browsertest.cc
+++ b/chrome/browser/site_details_browsertest.cc
@@ -1135,8 +1135,8 @@
   const Extension* extension1 = CreateExtension("Extension One", false);
 
   // Navigate the tab's first iframe to a resource of the extension. The
-  // extension iframe will be put in a separate BrowsingInstance (see
-  // https://crbug.com/522302) unless in the default process model.
+  // extension iframe will be put in the same BrowsingInstance as it is part
+  // of the frame tree.
   content::NavigateIframeToURL(
       tab, "child-0", extension1->GetResourceURL("/blank_iframe.html"));
   details = new TestMemoryDetails();
@@ -1144,7 +1144,7 @@
   if (content::AreAllSitesIsolatedForTesting()) {
     EXPECT_THAT(details->uma()->GetAllSamples(
                     "SiteIsolation.SiteInstancesPerBrowsingInstance"),
-                ElementsAre(Bucket(1, 1), Bucket(4, 1)));
+                ElementsAre(Bucket(5, 1)));
   } else if (extensions::IsIsolateExtensionsEnabled()) {
     EXPECT_THAT(details->uma()->GetAllSamples(
                     "SiteIsolation.SiteInstancesPerBrowsingInstance"),
@@ -1163,7 +1163,7 @@
   if (content::AreAllSitesIsolatedForTesting()) {
     EXPECT_THAT(details->uma()->GetAllSamples(
                     "SiteIsolation.SiteInstancesPerBrowsingInstance"),
-                ElementsAre(Bucket(1, 2), Bucket(4, 1)));
+                ElementsAre(Bucket(1, 1), Bucket(5, 1)));
   } else if (extensions::IsIsolateExtensionsEnabled()) {
     EXPECT_THAT(details->uma()->GetAllSamples(
                     "SiteIsolation.SiteInstancesPerBrowsingInstance"),
@@ -1174,9 +1174,8 @@
                 ElementsAre(Bucket(1, 2)));
   }
 
-  // Navigate the second iframe of the tab to the second extension. This will
-  // create a new BrowsingInstance again due to https://crbug.com/522302 for
-  // --site-per-process and --isolate-extensions.
+  // Navigate the second iframe of the tab to the second extension. It should
+  // stay in the same BrowsingInstance as the page.
   content::NavigateIframeToURL(
       tab, "child-1", extension2->GetResourceURL("/blank_iframe.html"));
   details = new TestMemoryDetails();
@@ -1184,7 +1183,7 @@
   if (content::AreAllSitesIsolatedForTesting()) {
     EXPECT_THAT(details->uma()->GetAllSamples(
                     "SiteIsolation.SiteInstancesPerBrowsingInstance"),
-                ElementsAre(Bucket(1, 3), Bucket(3, 1)));
+                ElementsAre(Bucket(1, 1), Bucket(5, 1)));
   } else if (extensions::IsIsolateExtensionsEnabled()) {
     EXPECT_THAT(details->uma()->GetAllSamples(
                     "SiteIsolation.SiteInstancesPerBrowsingInstance"),
diff --git a/chrome/browser/speech/tts_android.cc b/chrome/browser/speech/tts_android.cc
index dbec2f8..e8ec307e 100644
--- a/chrome/browser/speech/tts_android.cc
+++ b/chrome/browser/speech/tts_android.cc
@@ -11,6 +11,7 @@
 #include "base/memory/singleton.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/speech/tts_controller.h"
+#include "chrome/common/features.h"
 #include "jni/TtsPlatformImpl_jni.h"
 
 using base::android::AttachCurrentThread;
diff --git a/chrome/browser/speech/tts_android.h b/chrome/browser/speech/tts_android.h
index f6ce3b2..f38d674 100644
--- a/chrome/browser/speech/tts_android.h
+++ b/chrome/browser/speech/tts_android.h
@@ -8,6 +8,7 @@
 #include "base/android/jni_android.h"
 #include "base/android/scoped_java_ref.h"
 #include "chrome/browser/speech/tts_platform.h"
+#include "chrome/common/features.h"
 
 class TtsPlatformImplAndroid : public TtsPlatformImpl {
  public:
@@ -32,7 +33,9 @@
 
   // Static functions.
   static TtsPlatformImplAndroid* GetInstance();
+#if BUILDFLAG(ANDROID_JAVA_UI)
   static bool Register(JNIEnv* env);
+#endif
 
  private:
   friend struct base::DefaultSingletonTraits<TtsPlatformImplAndroid>;
diff --git a/chrome/browser/supervised_user/supervised_user_interstitial.cc b/chrome/browser/supervised_user/supervised_user_interstitial.cc
index 3810abd..510c783de 100644
--- a/chrome/browser/supervised_user/supervised_user_interstitial.cc
+++ b/chrome/browser/supervised_user/supervised_user_interstitial.cc
@@ -16,6 +16,7 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/supervised_user/supervised_user_service.h"
 #include "chrome/browser/supervised_user/supervised_user_service_factory.h"
+#include "chrome/common/features.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/grit/generated_resources.h"
 #include "components/infobars/core/infobar.h"
@@ -36,9 +37,9 @@
 #include "ui/base/webui/jstemplate_builder.h"
 #include "ui/base/webui/web_ui_util.h"
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
 #include "chrome/browser/supervised_user/child_accounts/child_account_feedback_reporter_android.h"
-#else
+#elif !defined(OS_ANDROID)
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/chrome_pages.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
@@ -340,7 +341,7 @@
         SupervisedUserURLFilter::GetBlockMessageID(reason_));
     std::string message = l10n_util::GetStringFUTF8(
         IDS_BLOCK_INTERSTITIAL_DEFAULT_FEEDBACK_TEXT, reason);
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
     ReportChildAccountFeedback(web_contents_, message, url_);
 #else
     chrome::ShowFeedbackPage(chrome::FindBrowserWithWebContents(web_contents_),
diff --git a/chrome/browser/sync/chrome_sync_client.cc b/chrome/browser/sync/chrome_sync_client.cc
index 7c5e70d2..7e389f9 100644
--- a/chrome/browser/sync/chrome_sync_client.cc
+++ b/chrome/browser/sync/chrome_sync_client.cc
@@ -29,6 +29,7 @@
 #include "chrome/browser/undo/bookmark_undo_service_factory.h"
 #include "chrome/browser/web_data_service_factory.h"
 #include "chrome/common/channel_info.h"
+#include "chrome/common/features.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/url_constants.h"
 #include "components/autofill/core/browser/webdata/autocomplete_syncable_service.h"
@@ -90,7 +91,7 @@
 #include "chrome/browser/spellchecker/spellcheck_service.h"
 #endif
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
 #include "chrome/browser/sync/glue/synced_window_delegates_getter_android.h"
 #endif
 
@@ -116,7 +117,7 @@
  public:
   explicit SyncSessionsClientImpl(Profile* profile) : profile_(profile) {
     window_delegates_getter_.reset(
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
         // Android doesn't have multi-profile support, so no need to pass the
         // profile in.
         new browser_sync::SyncedWindowDelegatesGetterAndroid());
@@ -262,11 +263,11 @@
 sync_driver::SyncApiComponentFactory::RegisterDataTypesMethod
 ChromeSyncClient::GetRegisterPlatformTypesCallback() {
   return base::Bind(
-#ifdef OS_ANDROID
+#if BUILDFLAG(ANDROID_JAVA_UI)
       &ChromeSyncClient::RegisterAndroidDataTypes,
 #else
       &ChromeSyncClient::RegisterDesktopDataTypes,
-#endif  // OS_ANDROID
+#endif  // BUILDFLAG(ANDROID_JAVA_UI)
       weak_ptr_factory_.GetWeakPtr());
 }
 
diff --git a/chrome/browser/sync/sessions/notification_service_sessions_router.cc b/chrome/browser/sync/sessions/notification_service_sessions_router.cc
index f66ec51..780ff29 100644
--- a/chrome/browser/sync/sessions/notification_service_sessions_router.cc
+++ b/chrome/browser/sync/sessions/notification_service_sessions_router.cc
@@ -12,6 +12,7 @@
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/sync/browser_synced_window_delegates_getter.h"
 #include "chrome/browser/ui/sync/tab_contents_synced_tab_delegate.h"
+#include "chrome/common/features.h"
 #include "components/history/core/browser/history_service.h"
 #include "components/sync_sessions/sync_sessions_client.h"
 #include "components/sync_sessions/synced_tab_delegate.h"
@@ -22,7 +23,7 @@
 #include "content/public/browser/notification_source.h"
 #include "content/public/browser/web_contents.h"
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
 #include "chrome/browser/android/tab_android.h"
 #endif
 
@@ -44,14 +45,14 @@
 
 SyncedTabDelegate* GetSyncedTabDelegateFromWebContents(
     content::WebContents* web_contents) {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
   TabAndroid* tab = TabAndroid::FromWebContents(web_contents);
   return tab ? tab->GetSyncedTabDelegate() : nullptr;
-#else   // !OS_ANDROID
+#else
   SyncedTabDelegate* delegate =
       TabContentsSyncedTabDelegate::FromWebContents(web_contents);
   return delegate;
-#endif  // OS_ANDROID
+#endif
 }
 
 }  // namespace
diff --git a/chrome/browser/translate/translate_manager_browsertest.cc b/chrome/browser/translate/translate_manager_browsertest.cc
index e30b1bce..4a7a6d9 100644
--- a/chrome/browser/translate/translate_manager_browsertest.cc
+++ b/chrome/browser/translate/translate_manager_browsertest.cc
@@ -61,7 +61,7 @@
 
 // Tests that the CLD (Compact Language Detection) works properly.
 IN_PROC_BROWSER_TEST_F(TranslateManagerBrowserTest, PageLanguageDetection) {
-  ASSERT_TRUE(test_server()->Start());
+  ASSERT_TRUE(embedded_test_server()->Start());
 
   // The InProcessBrowserTest opens a new tab, let's wait for that first.
   WaitUntilLanguageDetected();
@@ -73,7 +73,7 @@
   EXPECT_EQ("und", adopted_language);
 
   // Open a new tab with a page in English.
-  AddTabAtIndex(0, GURL(test_server()->GetURL("files/english_page.html")),
+  AddTabAtIndex(0, GURL(embedded_test_server()->GetURL("/english_page.html")),
                 ui::PAGE_TRANSITION_TYPED);
 
   ResetObserver();
@@ -92,7 +92,7 @@
 
   // Now navigate to a page in French.
   ui_test_utils::NavigateToURL(
-      browser(), GURL(test_server()->GetURL("files/french_page.html")));
+      browser(), GURL(embedded_test_server()->GetURL("/french_page.html")));
 
   WaitUntilLanguageDetected();
   adopted_language = GetLanguageFor(current_web_contents);
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 349a53d..91825ea9 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -46,6 +46,7 @@
   deps = [
     # NOTE: New dependencies should generally be added in the OS!="ios"
     # dependencies block below, rather than here.
+    "//base/debug:debugging_flags",
     "//chrome:extra_resources",
     "//chrome:resources",
     "//chrome:strings",
@@ -331,19 +332,19 @@
   }
 
   if (is_android) {
-    deps += [
-      "//chrome/browser:jni_headers",
-      "//crypto:platform",
-    ]
+    deps += [ "//crypto:platform" ]
 
     defines += [ "CHROME_BUILD_ID=\"$android_chrome_build_id\"" ]
 
-    if (!use_aura) {
+    if (android_java_ui) {
       sources +=
-          rebase_path(gypi_values.chrome_browser_ui_android_non_aura_sources,
+          rebase_path(gypi_values.chrome_browser_ui_android_java_ui_sources,
                       ".",
                       "//chrome")
-      deps += [ "//components/web_contents_delegate_android" ]
+      deps += [
+        "//chrome/browser:jni_headers",
+        "//components/web_contents_delegate_android",
+      ]
       deps -= [ "//ui/events" ]
     }
   }
@@ -456,6 +457,11 @@
     sources += rebase_path(gypi_values.chrome_browser_ui_app_list_sources,
                            ".",
                            "//chrome")
+    if (is_chromeos) {
+      sources += rebase_path(gypi_values.chrome_browser_ui_chromeos_arc_sources,
+                             ".",
+                             "//chrome")
+    }
     deps += [ "//ui/app_list" ]
   } else {
     sources += rebase_path(gypi_values.chrome_browser_ui_non_app_list_sources,
diff --git a/chrome/browser/ui/android/context_menu_helper.cc b/chrome/browser/ui/android/context_menu_helper.cc
index 87a6f39..68893d3 100644
--- a/chrome/browser/ui/android/context_menu_helper.cc
+++ b/chrome/browser/ui/android/context_menu_helper.cc
@@ -44,26 +44,24 @@
   Java_ContextMenuHelper_destroy(env, java_obj_.obj());
 }
 
-void ContextMenuHelper::ShowContextMenu(
+bool ContextMenuHelper::ShowContextMenu(
     const content::ContextMenuParams& params) {
   content::ContentViewCore* content_view_core =
       content::ContentViewCore::FromWebContents(web_contents_);
 
   if (!content_view_core)
-    return;
+    return false;
 
   base::android::ScopedJavaLocalRef<jobject> jcontent_view_core(
       content_view_core->GetJavaObject());
 
   if (jcontent_view_core.is_null())
-    return;
+    return false;
 
   JNIEnv* env = base::android::AttachCurrentThread();
   context_menu_params_ = params;
-  Java_ContextMenuHelper_showContextMenu(
-      env,
-      java_obj_.obj(),
-      jcontent_view_core.obj(),
+  return Java_ContextMenuHelper_showContextMenu(
+      env, java_obj_.obj(), jcontent_view_core.obj(),
       ContextMenuHelper::CreateJavaContextMenuParams(params).obj());
 }
 
diff --git a/chrome/browser/ui/android/context_menu_helper.h b/chrome/browser/ui/android/context_menu_helper.h
index 499eaad..3fa25b94 100644
--- a/chrome/browser/ui/android/context_menu_helper.h
+++ b/chrome/browser/ui/android/context_menu_helper.h
@@ -24,7 +24,7 @@
  public:
   ~ContextMenuHelper() override;
 
-  void ShowContextMenu(const content::ContextMenuParams& params);
+  bool ShowContextMenu(const content::ContextMenuParams& params);
 
   void SetPopulator(jobject jpopulator);
 
diff --git a/chrome/browser/ui/android/tab_contents/chrome_web_contents_view_delegate_android.cc b/chrome/browser/ui/android/tab_contents/chrome_web_contents_view_delegate_android.cc
index cc97dcc..473bc75 100644
--- a/chrome/browser/ui/android/tab_contents/chrome_web_contents_view_delegate_android.cc
+++ b/chrome/browser/ui/android/tab_contents/chrome_web_contents_view_delegate_android.cc
@@ -34,18 +34,19 @@
   if (params.is_editable && params.selection_text.empty()) {
     content::ContentViewCore* content_view_core =
         content::ContentViewCore::FromWebContents(web_contents_);
-    if (content_view_core) {
-      content_view_core->ShowPastePopup(params.selection_start.x(),
-                                        params.selection_start.y());
+    if (content_view_core &&
+        content_view_core->ShowPastePopup(params.selection_start.x(),
+                                          params.selection_start.y()))
       return;
-    }
+  } else {
+    // TODO(dtrainor, kouhei): Give WebView a Populator/delegate so it can use
+    // the same context menu code.
+    ContextMenuHelper* helper =
+        ContextMenuHelper::FromWebContents(web_contents_);
+    if (helper && helper->ShowContextMenu(params))
+      return;
   }
-
-  // TODO(dtrainor, kouhei): Give WebView a Populator/delegate so it can use the
-  // same context menu code.
-  ContextMenuHelper* helper = ContextMenuHelper::FromWebContents(web_contents_);
-  if (helper)
-    helper->ShowContextMenu(params);
+  web_contents_->NotifyContextMenuClosed(content::CustomContextMenuContext());
 }
 
 namespace chrome {
diff --git a/chrome/browser/ui/app_list/app_list_model_builder.cc b/chrome/browser/ui/app_list/app_list_model_builder.cc
new file mode 100644
index 0000000..9712158
--- /dev/null
+++ b/chrome/browser/ui/app_list/app_list_model_builder.cc
@@ -0,0 +1,64 @@
+// 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.
+
+#include "chrome/browser/ui/app_list/app_list_model_builder.h"
+
+#include "chrome/browser/ui/app_list/app_list_syncable_service.h"
+#include "ui/app_list/app_list_item.h"
+#include "ui/app_list/app_list_model.h"
+
+AppListModelBuilder::AppListModelBuilder(AppListControllerDelegate* controller,
+                                         const char* item_type)
+    : controller_(controller),
+      item_type_(item_type) {
+}
+
+AppListModelBuilder::~AppListModelBuilder() {
+  if (!service_)
+    model_->top_level_item_list()->RemoveObserver(this);
+}
+
+void AppListModelBuilder::InitializeWithService(
+    app_list::AppListSyncableService* service,
+    app_list::AppListModel* model) {
+  DCHECK(!service_ && !profile_);
+  model_ = model;
+  service_ = service;
+  profile_ = service->profile();
+
+  BuildModel();
+}
+
+void AppListModelBuilder::InitializeWithProfile(Profile* profile,
+                                                app_list::AppListModel* model) {
+  DCHECK(!service_ && !profile_);
+  model_ = model;
+  model_->top_level_item_list()->AddObserver(this);
+  profile_ = profile;
+
+  BuildModel();
+}
+
+void AppListModelBuilder::InsertApp(scoped_ptr<app_list::AppListItem> app) {
+  if (service_) {
+    service_->AddItem(app.Pass());
+    return;
+  }
+  model_->AddItem(app.Pass());
+}
+
+const app_list::AppListSyncableService::SyncItem*
+    AppListModelBuilder::GetSyncItem(const std::string& id) {
+  return service_ ? service_->GetSyncItem(id) : nullptr;
+}
+
+app_list::AppListItem* AppListModelBuilder::GetAppItem(const std::string& id) {
+  app_list::AppListItem* item = model_->FindItem(id);
+  if (item && item->GetItemType() != item_type_) {
+    VLOG(2) << "App Item matching id: " << id
+            << " has incorrect type: '" << item->GetItemType() << "'";
+    return nullptr;
+  }
+  return item;
+}
diff --git a/chrome/browser/ui/app_list/app_list_model_builder.h b/chrome/browser/ui/app_list/app_list_model_builder.h
new file mode 100644
index 0000000..0b53ea1
--- /dev/null
+++ b/chrome/browser/ui/app_list/app_list_model_builder.h
@@ -0,0 +1,75 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_APP_LIST_APP_LIST_MODEL_BUILDER_H_
+#define CHROME_BROWSER_UI_APP_LIST_APP_LIST_MODEL_BUILDER_H_
+
+#include <string>
+
+#include "base/macros.h"
+#include "chrome/browser/ui/app_list/app_list_syncable_service.h"
+#include "ui/app_list/app_list_item_list_observer.h"
+#include "ui/app_list/app_list_model.h"
+
+class AppListControllerDelegate;
+class Profile;
+
+// This abstract class populates and maintains the given |model| with
+// information from |profile| for the specific item type.
+class AppListModelBuilder : public app_list::AppListItemListObserver {
+ public:
+  // |controller| is owned by implementation of AppListService.
+  AppListModelBuilder(AppListControllerDelegate* controller,
+                      const char* item_type);
+   ~AppListModelBuilder() override;
+
+  // Initialize to use app-list sync and sets |service_| to |service|.
+  // |service| is the owner of this instance and |model|.
+  void InitializeWithService(app_list::AppListSyncableService* service,
+                             app_list::AppListModel* model);
+
+  // Initialize to use extension sync and sets |service_| to nullptr. Used in
+  // tests and when AppList sync is not enabled.
+  // app_list::AppListSyncableService is the owner of |model|
+  void InitializeWithProfile(Profile* profile, app_list::AppListModel* model);
+
+ protected:
+  // Builds the model with the current profile.
+  virtual void BuildModel() = 0;
+
+  app_list::AppListSyncableService* service() { return service_; }
+
+  Profile* profile() { return profile_; }
+
+  AppListControllerDelegate* controller() { return controller_; }
+
+  app_list::AppListModel* model() { return model_; }
+
+  // Inserts an app based on app ordinal prefs.
+  void InsertApp(scoped_ptr<app_list::AppListItem> app);
+
+  const app_list::AppListSyncableService::SyncItem* GetSyncItem(
+      const std::string& id);
+
+  // Returns app instance matching |id| or nullptr.
+  app_list::AppListItem* GetAppItem(const std::string& id);
+
+ private:
+  // Unowned pointers to the service that owns this and associated profile.
+  app_list::AppListSyncableService* service_ = nullptr;
+  Profile* profile_ = nullptr;
+
+  // Unowned pointer to the app list model.
+  app_list::AppListModel* model_ = nullptr;
+
+  // Unowned pointer to the app list controller.
+  AppListControllerDelegate* controller_;
+
+  // Global constant defined for each item type.
+  const char* item_type_;
+
+  DISALLOW_COPY_AND_ASSIGN(AppListModelBuilder);
+};
+
+#endif  // CHROME_BROWSER_UI_APP_LIST_APP_LIST_MODEL_BUILDER_H_
diff --git a/chrome/browser/ui/app_list/app_list_syncable_service.cc b/chrome/browser/ui/app_list/app_list_syncable_service.cc
index 7ab733b..909a17b 100644
--- a/chrome/browser/ui/app_list/app_list_syncable_service.cc
+++ b/chrome/browser/ui/app_list/app_list_syncable_service.cc
@@ -36,6 +36,8 @@
 #if defined(OS_CHROMEOS)
 #include "chrome/browser/chromeos/file_manager/app_id.h"
 #include "chrome/browser/chromeos/genius_app/app_id.h"
+#include "chrome/browser/ui/app_list/arc/arc_app_item.h"
+#include "chrome/browser/ui/app_list/arc/arc_app_model_builder.h"
 #endif
 
 using syncer::SyncChange;
@@ -132,6 +134,10 @@
   const char* item_type = item->GetItemType();
   if (item_type == ExtensionAppItem::kItemType) {
     *type = sync_pb::AppListSpecifics::TYPE_APP;
+#if defined(OS_CHROMEOS)
+  } else if (item_type == ArcAppItem::kItemType) {
+    *type = sync_pb::AppListSpecifics::TYPE_APP;
+#endif
   } else if (item_type == AppListFolderItem::kItemType) {
     *type = sync_pb::AppListSpecifics::TYPE_FOLDER;
   } else {
@@ -265,14 +271,23 @@
   if (service)
     controller = service->GetControllerDelegate();
   apps_builder_.reset(new ExtensionAppModelBuilder(controller));
+#if defined(OS_CHROMEOS)
+  arc_apps_builder_.reset(new ArcAppModelBuilder(controller));
+#endif
   DCHECK(profile_);
   if (app_list::switches::IsAppListSyncEnabled()) {
     VLOG(1) << this << ": AppListSyncableService: InitializeWithService.";
     SyncStarted();
     apps_builder_->InitializeWithService(this, model_.get());
+#if defined(OS_CHROMEOS)
+    arc_apps_builder_->InitializeWithService(this, model_.get());
+#endif
   } else {
     VLOG(1) << this << ": AppListSyncableService: InitializeWithProfile.";
     apps_builder_->InitializeWithProfile(profile_, model_.get());
+#if defined(OS_CHROMEOS)
+    arc_apps_builder_->InitializeWithProfile(profile_, model_.get());
+#endif
   }
 
   model_pref_updater_.reset(
diff --git a/chrome/browser/ui/app_list/app_list_syncable_service.h b/chrome/browser/ui/app_list/app_list_syncable_service.h
index 3407616..c4258051 100644
--- a/chrome/browser/ui/app_list/app_list_syncable_service.h
+++ b/chrome/browser/ui/app_list/app_list_syncable_service.h
@@ -18,6 +18,10 @@
 #include "sync/api/syncable_service.h"
 #include "sync/protocol/app_list_specifics.pb.h"
 
+#if defined(OS_CHROMEOS)
+class ArcAppModelBuilder;
+#endif
+
 class DriveAppProvider;
 class ExtensionAppModelBuilder;
 class Profile;
@@ -200,6 +204,9 @@
   scoped_ptr<ModelObserver> model_observer_;
   scoped_ptr<ModelPrefUpdater> model_pref_updater_;
   scoped_ptr<ExtensionAppModelBuilder> apps_builder_;
+#if defined(OS_CHROMEOS)
+  scoped_ptr<ArcAppModelBuilder> arc_apps_builder_;
+#endif
   scoped_ptr<syncer::SyncChangeProcessor> sync_processor_;
   scoped_ptr<syncer::SyncErrorFactory> sync_error_handler_;
   SyncItemMap sync_items_;
diff --git a/chrome/browser/ui/app_list/app_list_syncable_service_factory.cc b/chrome/browser/ui/app_list/app_list_syncable_service_factory.cc
index 2c96dc22..c2e2eb1 100644
--- a/chrome/browser/ui/app_list/app_list_syncable_service_factory.cc
+++ b/chrome/browser/ui/app_list/app_list_syncable_service_factory.cc
@@ -18,6 +18,7 @@
 
 #if defined(OS_CHROMEOS)
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
+#include "chrome/browser/ui/app_list/arc/arc_app_list_prefs_factory.h"
 #endif
 
 namespace app_list {
@@ -57,6 +58,9 @@
   FactorySet dependent_factories;
   dependent_factories.insert(
       extensions::ExtensionsBrowserClient::Get()->GetExtensionSystemFactory());
+#if defined(OS_CHROMEOS)
+  dependent_factories.insert(ArcAppListPrefsFactory::GetInstance());
+#endif
   DriveAppProvider::AppendDependsOnFactories(&dependent_factories);
   for (FactorySet::iterator it = dependent_factories.begin();
        it != dependent_factories.end();
diff --git a/chrome/browser/ui/app_list/arc/arc_app_icon.cc b/chrome/browser/ui/app_list/arc/arc_app_icon.cc
new file mode 100644
index 0000000..26adfab
--- /dev/null
+++ b/chrome/browser/ui/app_list/arc/arc_app_icon.cc
@@ -0,0 +1,284 @@
+// 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.
+
+#include "chrome/browser/ui/app_list/arc/arc_app_icon.h"
+
+#include <algorithm>
+
+#include "base/bind.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/task_runner_util.h"
+#include "chrome/browser/image_decoder.h"
+#include "chrome/browser/ui/app_list/arc/arc_app_list_prefs.h"
+#include "content/public/browser/browser_thread.h"
+#include "extensions/grit/extensions_browser_resources.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/gfx/geometry/size.h"
+#include "ui/gfx/image/image_skia_source.h"
+
+namespace {
+
+bool g_disable_decoding = false;
+
+}  // namespace
+
+////////////////////////////////////////////////////////////////////////////////
+// ArcAppIcon::ReadResult
+
+struct ArcAppIcon::ReadResult {
+  enum class Status {
+    OK,
+    FAIL,
+    REQUEST_TO_INSTALL,
+  };
+
+  // Used for fail results or for the requests to install an icon.
+  ReadResult(Status status, ui::ScaleFactor scale_factor)
+      : status(status), scale_factor(scale_factor) {
+    DCHECK(status == Status::FAIL || status == Status::REQUEST_TO_INSTALL);
+  }
+
+  // Used for successful results.
+  ReadResult(ui::ScaleFactor scale_factor,
+             const std::string& unsafe_icon_data)
+      : status(Status::OK),
+        scale_factor(scale_factor),
+        unsafe_icon_data(unsafe_icon_data) {
+  }
+
+  Status status;
+  ui::ScaleFactor scale_factor;
+  std::string unsafe_icon_data;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// ArcAppIcon::Source
+
+class ArcAppIcon::Source : public gfx::ImageSkiaSource {
+ public:
+  explicit Source(const base::WeakPtr<ArcAppIcon>& host);
+  ~Source() override;
+
+ private:
+  // gfx::ImageSkiaSource overrides:
+  gfx::ImageSkiaRep GetImageForScale(float scale) override;
+
+  // Used to load images asynchronously. NULLed out when the ArcAppIcon is
+  // destroyed.
+  base::WeakPtr<ArcAppIcon> host_;
+
+  DISALLOW_COPY_AND_ASSIGN(Source);
+};
+
+ArcAppIcon::Source::Source(const base::WeakPtr<ArcAppIcon>& host)
+    : host_(host) {
+}
+
+ArcAppIcon::Source::~Source() {
+}
+
+gfx::ImageSkiaRep ArcAppIcon::Source::GetImageForScale(float scale) {
+  if (host_)
+    host_->LoadForScaleFactor(ui::GetSupportedScaleFactor(scale));
+
+  // Host loads icon asynchronously, so use default icon so far.
+  const gfx::ImageSkia* default_image = ResourceBundle::GetSharedInstance().
+      GetImageSkiaNamed(IDR_APP_DEFAULT_ICON);
+  CHECK(default_image);
+
+  return default_image->GetRepresentation(scale);
+}
+
+class ArcAppIcon::DecodeRequest : public ImageDecoder::ImageRequest {
+ public:
+  DecodeRequest(const base::WeakPtr<ArcAppIcon>& host,
+                int dimension,
+                ui::ScaleFactor scale_factor);
+  ~DecodeRequest() override;
+
+  // ImageDecoder::ImageRequest
+  void OnImageDecoded(const SkBitmap& bitmap) override;
+  void OnDecodeImageFailed() override;
+ private:
+  base::WeakPtr<ArcAppIcon> host_;
+  int dimension_;
+  ui::ScaleFactor scale_factor_;
+
+  DISALLOW_COPY_AND_ASSIGN(DecodeRequest);
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// ArcAppIcon::DecodeRequest
+
+ArcAppIcon::DecodeRequest::DecodeRequest(const base::WeakPtr<ArcAppIcon>& host,
+                                         int dimension,
+                                         ui::ScaleFactor scale_factor)
+    : host_(host),
+      dimension_(dimension),
+      scale_factor_(scale_factor) {
+}
+
+ArcAppIcon::DecodeRequest::~DecodeRequest() {
+}
+
+void ArcAppIcon::DecodeRequest::OnImageDecoded(const SkBitmap& bitmap) {
+  DCHECK(!bitmap.isNull() && !bitmap.empty());
+
+  if (!host_)
+    return;
+
+  int expected_dim = static_cast<int>(
+      ui::GetScaleForScaleFactor(scale_factor_) * dimension_ + 0.5f);
+  if (bitmap.width() != expected_dim || bitmap.height() != expected_dim) {
+    VLOG(2) << "Decoded ARC icon has unexpected dimension "
+            << bitmap.width() << "x" << bitmap.height() << ". Expected "
+            << expected_dim << "x" << ".";
+    host_->DiscardDecodeRequest(this);
+    return;
+  }
+
+  gfx::ImageSkia image_skia;
+  image_skia.AddRepresentation(gfx::ImageSkiaRep(
+      bitmap,
+      ui::GetScaleForScaleFactor(scale_factor_)));
+
+  host_->Update(&image_skia);
+  host_->DiscardDecodeRequest(this);
+}
+
+void ArcAppIcon::DecodeRequest::OnDecodeImageFailed() {
+  VLOG(2) << "Failed to decode ARC icon.";
+
+  if (!host_)
+    return;
+
+  host_->DiscardDecodeRequest(this);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// ArcAppIcon
+
+// static
+void ArcAppIcon::DisableDecodingForTesting() {
+  g_disable_decoding = true;
+}
+
+ArcAppIcon::ArcAppIcon(content::BrowserContext* context,
+                       const std::string& app_id,
+                       int resource_size_in_dip,
+                       Observer* observer)
+    : context_(context),
+      app_id_(app_id),
+      resource_size_in_dip_(resource_size_in_dip),
+      observer_(observer),
+      weak_ptr_factory_(this) {
+  CHECK(observer_ != nullptr);
+  source_ = new Source(weak_ptr_factory_.GetWeakPtr());
+  gfx::Size resource_size(resource_size_in_dip, resource_size_in_dip);
+  image_skia_ = gfx::ImageSkia(source_, resource_size);
+}
+
+ArcAppIcon::~ArcAppIcon() {
+}
+
+void ArcAppIcon::LoadForScaleFactor(ui::ScaleFactor scale_factor) {
+  ArcAppListPrefs* prefs = ArcAppListPrefs::Get(context_);
+
+  base::FilePath path = prefs->GetIconPath(app_id_, scale_factor);
+  if (path.empty())
+    return;
+
+  base::PostTaskAndReplyWithResult(content::BrowserThread::GetBlockingPool(),
+                                   FROM_HERE,
+                                   base::Bind(&ArcAppIcon::ReadOnFileThread,
+                                              scale_factor,
+                                              path),
+                                   base::Bind(&ArcAppIcon::OnIconRead,
+                                              weak_ptr_factory_.GetWeakPtr()));
+}
+
+void ArcAppIcon::RequestIcon(ui::ScaleFactor scale_factor) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  ArcAppListPrefs* prefs = ArcAppListPrefs::Get(context_);
+
+  // ArcAppListPrefs notifies ArcAppModelBuilder via Observer when icon is ready
+  // and ArcAppModelBuilder refreshes the icon of the corresponding item by
+  // calling LoadScaleFactor.
+  prefs->RequestIcon(app_id_, scale_factor);
+}
+
+// static
+scoped_ptr<ArcAppIcon::ReadResult> ArcAppIcon::ReadOnFileThread(
+    ui::ScaleFactor scale_factor,
+    const base::FilePath& path) {
+  DCHECK(content::BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
+  DCHECK(!path.empty());
+
+  if (!base::PathExists(path))
+    return make_scoped_ptr(new ArcAppIcon::ReadResult(
+        ArcAppIcon::ReadResult::Status::REQUEST_TO_INSTALL, scale_factor));
+
+  // Read the file from disk.
+  std::string unsafe_icon_data;
+  if (!base::ReadFileToString(path, &unsafe_icon_data)) {
+    VLOG(2) << "Failed to read an ARC icon from file " << path.MaybeAsASCII();
+    return make_scoped_ptr(new ArcAppIcon::ReadResult(
+        ArcAppIcon::ReadResult::Status::FAIL, scale_factor));
+  }
+
+  return make_scoped_ptr(new ArcAppIcon::ReadResult(scale_factor,
+                                                    unsafe_icon_data));
+}
+
+void ArcAppIcon::OnIconRead(scoped_ptr<ArcAppIcon::ReadResult> read_result) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+  switch (read_result->status) {
+  case ReadResult::Status::OK:
+    if (!g_disable_decoding) {
+      decode_requests_.push_back(
+          new DecodeRequest(weak_ptr_factory_.GetWeakPtr(),
+                            resource_size_in_dip_,
+                            read_result->scale_factor));
+      ImageDecoder::Start(decode_requests_.back(),
+                          read_result->unsafe_icon_data);
+    }
+    break;
+  case ReadResult::Status::FAIL:
+    break;
+  case ReadResult::Status::REQUEST_TO_INSTALL:
+    RequestIcon(read_result->scale_factor);
+    break;
+  default:
+    NOTREACHED();
+  }
+}
+
+void ArcAppIcon::Update(const gfx::ImageSkia* image) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  CHECK(image && !image->isNull());
+
+  std::vector<gfx::ImageSkiaRep> reps = image->image_reps();
+  for (const auto& image_rep : reps) {
+    if (ui::IsSupportedScale(image_rep.scale())) {
+      image_skia_.RemoveRepresentation(image_rep.scale());
+      image_skia_.AddRepresentation(image_rep);
+    }
+  }
+
+  image_ = gfx::Image(image_skia_);
+
+  observer_->OnIconUpdated();
+}
+
+void ArcAppIcon::DiscardDecodeRequest(DecodeRequest* request) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+  ScopedVector<DecodeRequest>::iterator it = std::find(decode_requests_.begin(),
+                                                       decode_requests_.end(),
+                                                       request);
+  CHECK(it != decode_requests_.end());
+  decode_requests_.erase(it);
+}
diff --git a/chrome/browser/ui/app_list/arc/arc_app_icon.h b/chrome/browser/ui/app_list/arc/arc_app_icon.h
new file mode 100644
index 0000000..e3f09b82
--- /dev/null
+++ b/chrome/browser/ui/app_list/arc/arc_app_icon.h
@@ -0,0 +1,111 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_APP_LIST_ARC_ARC_APP_ICON_H_
+#define CHROME_BROWSER_UI_APP_LIST_ARC_ARC_APP_ICON_H_
+
+#include <string>
+
+#include "base/macros.h"
+#include "base/memory/scoped_vector.h"
+#include "base/memory/weak_ptr.h"
+#include "ui/base/layout.h"
+#include "ui/gfx/image/image.h"
+#include "ui/gfx/image/image_skia.h"
+
+namespace base {
+class FilePath;
+}
+
+namespace content {
+class BrowserContext;
+}
+
+// A class that provides an ImageSkia for UI code to use. It handles ARC app
+// icon resource loading, screen scale factor change etc. UI code that uses
+// ARC app icon should host this class.
+class ArcAppIcon {
+ public:
+  class Observer {
+   public:
+    // Invoked when a new image rep for an additional scale factor
+    // is loaded and added to |image|.
+    virtual void OnIconUpdated() = 0;
+
+   protected:
+    virtual ~Observer() {}
+  };
+
+  ArcAppIcon(content::BrowserContext* context,
+             const std::string& app_id,
+             int resource_size_in_dip,
+             Observer* observer);
+  ~ArcAppIcon();
+
+  gfx::Image image() const { return image_; }
+  const gfx::ImageSkia& image_skia() const { return image_skia_; }
+
+  // Icon loading is performed in several steps. It is initiated by
+  // LoadImageForScaleFactor request that specifies a required scale factor.
+  // ArcAppListPrefs is used to resolve a path to resource. Content of file is
+  // asynchronously read in context of browser file thread. On successful read,
+  // an icon data is decoded to an image in the special utility process.
+  // DecodeRequest is used to interact with the utility process, and each
+  // active request is stored at |decode_requests_| vector. When decoding is
+  // complete, results are returned in context of UI thread, and corresponding
+  // request is removed from |decode_requests_|. In case of some requests are
+  // not completed by the time of deleting this icon, they are automatically
+  // canceled.
+  // In case of the icon file is not available this requests ArcAppListPrefs to
+  // install required resource from ARC side. ArcAppListPrefs notifies UI items
+  // that new icon is available and corresponding item should invoke
+  // LoadImageForScaleFactor again.
+  void LoadForScaleFactor(ui::ScaleFactor scale_factor);
+
+  // Disables decoding requests when unit tests are executed. This is done to
+  // avoid two problems. Problems come because icons are decoded at a separate
+  // process created by ImageDecoder. ImageDecoder has 5 seconds delay to stop
+  // since the last request (see its kBatchModeTimeoutSeconds for more details).
+  // This is unacceptably long for unit tests because the test framework waits
+  // until external process is finished. Another problem happens when we issue
+  // a decoding request, but the process has not started its processing yet by
+  // the time when a test exits. This might cause situation when
+  // g_one_utility_thread_lock from in_process_utility_thread.cc gets released
+  // in an acquired state which is crash condition in debug builds.
+  static void DisableDecodingForTesting();
+
+ private:
+  class Source;
+  class DecodeRequest;
+  struct ReadResult;
+
+  void RequestIcon(ui::ScaleFactor scale_factor);
+  static scoped_ptr<ArcAppIcon::ReadResult> ReadOnFileThread(
+      ui::ScaleFactor scale_factor,
+      const base::FilePath& path);
+  void OnIconRead(scoped_ptr<ArcAppIcon::ReadResult> read_result);
+  void Update(const gfx::ImageSkia* image);
+  void DiscardDecodeRequest(DecodeRequest* request);
+
+  content::BrowserContext* context_;
+  std::string app_id_;
+  const int resource_size_in_dip_;
+  Observer* observer_;
+
+  Source* source_ = nullptr;  // Owned by ImageSkia storage.
+  gfx::ImageSkia image_skia_;
+
+  // The image wrapper around |image_skia_|.
+  // Note: this is reset each time a new representation is loaded.
+  gfx::Image image_;
+
+  // Contains pending image decode requests.
+  ScopedVector<DecodeRequest> decode_requests_;
+
+  base::WeakPtrFactory<ArcAppIcon> weak_ptr_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(ArcAppIcon);
+};
+
+#endif  // CHROME_BROWSER_UI_APP_LIST_ARC_ARC_APP_ICON_H_
diff --git a/chrome/browser/ui/app_list/arc/arc_app_item.cc b/chrome/browser/ui/app_list/arc/arc_app_item.cc
new file mode 100644
index 0000000..2e1a312
--- /dev/null
+++ b/chrome/browser/ui/app_list/arc/arc_app_item.cc
@@ -0,0 +1,120 @@
+// 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.
+
+#include "chrome/browser/ui/app_list/arc/arc_app_item.h"
+
+#include "chrome/browser/ui/app_list/arc/arc_app_list_prefs.h"
+#include "components/arc/arc_bridge_service.h"
+#include "content/public/browser/browser_thread.h"
+#include "extensions/browser/app_sorting.h"
+#include "extensions/browser/extension_prefs.h"
+#include "ui/app_list/app_list_constants.h"
+#include "ui/gfx/color_utils.h"
+#include "ui/gfx/image/image_skia_operations.h"
+
+namespace {
+
+gfx::ImageSkia CreateDisabledIcon(const gfx::ImageSkia& icon) {
+  const color_utils::HSL shift = {-1, 0, 0.6};
+  return gfx::ImageSkiaOperations::CreateHSLShiftedImage(icon, shift);
+}
+
+extensions::AppSorting* GetAppSorting(content::BrowserContext* context) {
+  return extensions::ExtensionPrefs::Get(context)->app_sorting();
+}
+
+}  // namespace
+
+// static
+const char ArcAppItem::kItemType[] = "ArcAppItem";
+
+ArcAppItem::ArcAppItem(
+    content::BrowserContext* context,
+    const app_list::AppListSyncableService::SyncItem* sync_item,
+    const std::string& id,
+    const std::string& name,
+    bool ready)
+    : app_list::AppListItem(id),
+      context_(context),
+      ready_(ready) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+  arc_app_icon_.reset(new ArcAppIcon(context_,
+                                     id,
+                                     app_list::kGridIconDimension,
+                                     this));
+
+  SetName(name);
+  UpdateIcon();
+
+  if (sync_item && sync_item->item_ordinal.IsValid()) {
+    // An existing synced position exists, use that.
+    set_position(sync_item->item_ordinal);
+  } else {
+    // There is an ExtensionAppItem that uses extension::AppSorting to order
+    // its element. There is no commonly available sorting mechanism for app
+    // ordering so use the only one available from extension subsystem.
+    // Page is is the earliest non-full page.
+    const syncer::StringOrdinal& page =
+        GetAppSorting(context_)->GetNaturalAppPageOrdinal();
+    // And get next available pos in this page.
+    const syncer::StringOrdinal& pos =
+       GetAppSorting(context_)->CreateNextAppLaunchOrdinal(page);
+    set_position(pos);
+  }
+}
+
+ArcAppItem::~ArcAppItem() {
+}
+
+const char* ArcAppItem::GetItemType() const {
+  return ArcAppItem::kItemType;
+}
+
+void ArcAppItem::Activate(int event_flags) {
+  DCHECK(ready_);
+
+  ArcAppListPrefs* prefs = ArcAppListPrefs::Get(context_);
+  scoped_ptr<ArcAppListPrefs::AppInfo> app_info = prefs->GetApp(id());
+  if (!app_info) {
+    VLOG(2) << "Cannot launch unavailable app:" << id() << ".";
+    return;
+  }
+
+  arc::ArcBridgeService* bridge_service = arc::ArcBridgeService::Get();
+  if (!bridge_service ||
+      bridge_service->state() != arc::ArcBridgeService::State::READY) {
+    VLOG(2) << "Cannot launch app: " << app_info->package
+            << ". Bridge service is not ready.";
+    return;
+  }
+
+  bridge_service->LaunchApp(app_info->package, app_info->activity);
+}
+
+void ArcAppItem::SetReady(bool ready) {
+  if (ready_ == ready)
+    return;
+
+  ready_ = ready;
+  UpdateIcon();
+}
+
+void ArcAppItem::SetName(const std::string& name) {
+  SetNameAndShortName(name, name);
+}
+
+void ArcAppItem::UpdateIcon() {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+  gfx::ImageSkia icon = arc_app_icon_->image_skia();
+  if (!ready_)
+    icon = CreateDisabledIcon(icon);
+
+  SetIcon(icon);
+}
+
+void ArcAppItem::OnIconUpdated() {
+  UpdateIcon();
+}
diff --git a/chrome/browser/ui/app_list/arc/arc_app_item.h b/chrome/browser/ui/app_list/arc/arc_app_item.h
new file mode 100644
index 0000000..22342bd
--- /dev/null
+++ b/chrome/browser/ui/app_list/arc/arc_app_item.h
@@ -0,0 +1,57 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_APP_LIST_ARC_ARC_APP_ITEM_H_
+#define CHROME_BROWSER_UI_APP_LIST_ARC_ARC_APP_ITEM_H_
+
+#include <string>
+
+#include "base/macros.h"
+#include "chrome/browser/ui/app_list/app_list_syncable_service.h"
+#include "chrome/browser/ui/app_list/arc/arc_app_icon.h"
+#include "ui/app_list/app_list_item.h"
+
+namespace content {
+class BrowserContext;
+}  // content
+
+// ArcAppItem represents an ARC app in app list.
+class ArcAppItem : public app_list::AppListItem,
+                   public ArcAppIcon::Observer {
+ public:
+  static const char kItemType[];
+
+  ArcAppItem(content::BrowserContext* context,
+             const app_list::AppListSyncableService::SyncItem* sync_item,
+             const std::string& id,
+             const std::string& name,
+             bool ready);
+  ~ArcAppItem() override;
+
+  void SetName(const std::string& name);
+
+  void Activate(int event_flags) override;
+  const char* GetItemType() const override;
+
+  ArcAppIcon* arc_app_icon() { return arc_app_icon_.get(); }
+
+  bool ready() const { return ready_; }
+
+  void SetReady(bool ready);
+
+  // ArcAppIcon::Observer
+  void OnIconUpdated() override;
+
+ private:
+  // Updates the app item's icon, if necessary making it gray.
+  void UpdateIcon();
+
+  content::BrowserContext* context_;
+  bool ready_;
+  scoped_ptr<ArcAppIcon> arc_app_icon_;
+
+  DISALLOW_COPY_AND_ASSIGN(ArcAppItem);
+};
+
+#endif  // CHROME_BROWSER_UI_APP_LIST_ARC_ARC_APP_ITEM_H_
diff --git a/chrome/browser/ui/app_list/arc/arc_app_list_prefs.cc b/chrome/browser/ui/app_list/arc/arc_app_list_prefs.cc
new file mode 100644
index 0000000..157ec45
--- /dev/null
+++ b/chrome/browser/ui/app_list/arc/arc_app_list_prefs.cc
@@ -0,0 +1,376 @@
+// 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.
+
+#include "chrome/browser/ui/app_list/arc/arc_app_list_prefs.h"
+
+#include "base/files/file_util.h"
+#include "base/prefs/scoped_user_pref_update.h"
+#include "base/task_runner_util.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/app_list/arc/arc_app_list_prefs_factory.h"
+#include "chrome/common/pref_names.h"
+#include "components/crx_file/id_util.h"
+#include "components/pref_registry/pref_registry_syncable.h"
+#include "content/public/browser/browser_thread.h"
+
+namespace {
+
+const char kName[] = "name";
+const char kPackage[] = "package";
+const char kActivity[] = "activity";
+
+// Provider of write access to a dictionary storing ARC app prefs.
+class ScopedArcAppListPrefUpdate : public DictionaryPrefUpdate {
+ public:
+  ScopedArcAppListPrefUpdate(PrefService* service, const std::string& id)
+      : DictionaryPrefUpdate(service, prefs::kArcApps),
+        id_(id) {}
+
+  ~ScopedArcAppListPrefUpdate() override {}
+
+  // DictionaryPrefUpdate overrides:
+  base::DictionaryValue* Get() override {
+    base::DictionaryValue* dict = DictionaryPrefUpdate::Get();
+    base::DictionaryValue* app = nullptr;
+    if (!dict->GetDictionary(id_, &app)) {
+      app = new base::DictionaryValue();
+      dict->SetWithoutPathExpansion(id_, app);
+    }
+    return app;
+  }
+
+ private:
+  const std::string id_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedArcAppListPrefUpdate);
+};
+
+bool InstallIconFromFileThread(const std::string& app_id,
+                               ui::ScaleFactor scale_factor,
+                               const base::FilePath& icon_path,
+                               const std::vector<uint8>& content_png) {
+  DCHECK(content::BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
+  DCHECK(!content_png.empty());
+
+  base::CreateDirectory(icon_path.DirName());
+
+  int wrote = base::WriteFile(icon_path,
+                              reinterpret_cast<const char*>(&content_png[0]),
+                              content_png.size());
+  if (wrote != static_cast<int>(content_png.size())) {
+    VLOG(2) << "Failed to write ARC icon file: " << icon_path.MaybeAsASCII()
+            << ".";
+    if (!base::DeleteFile(icon_path, false))
+      VLOG(2) << "Couldn't delete broken icon file" << icon_path.MaybeAsASCII()
+              << ".";
+    return false;
+  }
+
+  return true;
+}
+
+}  // namespace
+
+// static
+ArcAppListPrefs* ArcAppListPrefs::Create(const base::FilePath& base_path,
+                                         PrefService* prefs) {
+  return new ArcAppListPrefs(base_path, prefs);
+}
+
+// static
+void ArcAppListPrefs::RegisterProfilePrefs(
+    user_prefs::PrefRegistrySyncable* registry) {
+  registry->RegisterDictionaryPref(
+      prefs::kArcApps,
+      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
+}
+
+// static
+ArcAppListPrefs* ArcAppListPrefs::Get(content::BrowserContext* context) {
+  return ArcAppListPrefsFactory::GetInstance()->GetForBrowserContext(context);
+}
+
+// static
+std::string ArcAppListPrefs::GetAppId(const std::string& package,
+                                      const std::string& activity) {
+  std::string input = package + "#" + activity;
+  return crx_file::id_util::GenerateId(input);
+}
+
+ArcAppListPrefs::ArcAppListPrefs(const base::FilePath& base_path,
+                                 PrefService* prefs)
+    : prefs_(prefs),
+      weak_ptr_factory_(this) {
+  base_path_ = base_path.AppendASCII(prefs::kArcApps);
+
+  arc::ArcBridgeService* bridge_service = arc::ArcBridgeService::Get();
+  if (!bridge_service) {
+    VLOG(2) << "Bridge service is not available. Cannot init.";
+    return;
+  }
+
+  bridge_service->AddObserver(this);
+  bridge_service->AddAppObserver(this);
+  OnStateChanged(bridge_service->state());
+}
+
+ArcAppListPrefs::~ArcAppListPrefs() {
+  arc::ArcBridgeService* bridge_service = arc::ArcBridgeService::Get();
+  if (bridge_service) {
+    bridge_service->RemoveAppObserver(this);
+    bridge_service->RemoveObserver(this);
+  }
+}
+
+base::FilePath ArcAppListPrefs::GetIconPath(
+    const std::string& app_id,
+    ui::ScaleFactor scale_factor) const {
+  base::FilePath app_path = base_path_.AppendASCII(app_id);
+  switch (scale_factor) {
+  case ui::SCALE_FACTOR_100P:
+    return app_path.AppendASCII("icon_100p.png");
+  case ui::SCALE_FACTOR_125P:
+    return app_path.AppendASCII("icon_125p.png");
+  case ui::SCALE_FACTOR_133P:
+    return app_path.AppendASCII("icon_133p.png");
+  case ui::SCALE_FACTOR_140P:
+    return app_path.AppendASCII("icon_140p.png");
+  case ui::SCALE_FACTOR_150P:
+    return app_path.AppendASCII("icon_150p.png");
+  case ui::SCALE_FACTOR_180P:
+    return app_path.AppendASCII("icon_180p.png");
+  case ui::SCALE_FACTOR_200P:
+    return app_path.AppendASCII("icon_200p.png");
+  case ui::SCALE_FACTOR_250P:
+    return app_path.AppendASCII("icon_250p.png");
+  case ui::SCALE_FACTOR_300P:
+    return app_path.AppendASCII("icon_300p.png");
+  default:
+    NOTREACHED();
+    return base::FilePath();
+  }
+}
+
+void ArcAppListPrefs::RequestIcon(const std::string& app_id,
+                                  ui::ScaleFactor scale_factor) {
+  if (!IsRegistered(app_id)) {
+    VLOG(2) << "Request to load icon for non-registered app: "
+            <<  app_id << ".";
+    return;
+  }
+
+  // In case app is not ready, defer this request.
+  if (!ready_apps_.count(app_id)) {
+    request_icon_deferred_[app_id] =
+        request_icon_deferred_[app_id] | 1 << scale_factor;
+    return;
+  }
+
+  arc::ArcBridgeService* bridge_service = arc::ArcBridgeService::Get();
+  if (!bridge_service ||
+      bridge_service->state() != arc::ArcBridgeService::State::READY) {
+    VLOG(2) << "Request to load icon when bridge service is not ready: "
+            <<  app_id << ".";
+    return;
+  }
+
+  scoped_ptr<AppInfo> app_info = GetApp(app_id);
+  if (!app_info) {
+    VLOG(2) << "Failed to get app info: " <<  app_id << ".";
+    return;
+  }
+
+  bridge_service->RequestAppIcon(app_info->package,
+                                 app_info->activity,
+                                 static_cast<arc::ScaleFactor>(scale_factor));
+}
+
+void ArcAppListPrefs::AddObserver(Observer* observer) {
+  observer_list_.AddObserver(observer);
+}
+
+void ArcAppListPrefs::RemoveObserver(Observer* observer) {
+  observer_list_.RemoveObserver(observer);
+}
+
+std::vector<std::string> ArcAppListPrefs::GetAppIds() const {
+  std::vector<std::string> ids;
+
+  // crx_file::id_util is de-factor utility for id generation.
+  const base::DictionaryValue* apps = prefs_->GetDictionary(prefs::kArcApps);
+  for (base::DictionaryValue::Iterator app_id(*apps);
+       !app_id.IsAtEnd(); app_id.Advance()) {
+    if (!crx_file::id_util::IdIsValid(app_id.key()))
+      continue;
+    ids.push_back(app_id.key());
+  }
+
+  return ids;
+}
+
+scoped_ptr<ArcAppListPrefs::AppInfo> ArcAppListPrefs::GetApp(
+    const std::string& app_id) const {
+  const base::DictionaryValue* app = nullptr;
+  const base::DictionaryValue* apps = prefs_->GetDictionary(prefs::kArcApps);
+  if (!apps || !apps->GetDictionaryWithoutPathExpansion(app_id, &app))
+    return scoped_ptr<AppInfo>();
+
+  std::string name;
+  std::string package;
+  std::string activity;
+  app->GetString(kName, &name);
+  app->GetString(kPackage, &package);
+  app->GetString(kActivity, &activity);
+  scoped_ptr<AppInfo> app_info(new AppInfo(name,
+                                           package,
+                                           activity,
+                                           ready_apps_.count(app_id) > 0));
+
+  return app_info.Pass();
+}
+
+bool ArcAppListPrefs::IsRegistered(const std::string& app_id) {
+  const base::DictionaryValue* app = nullptr;
+  const base::DictionaryValue* apps = prefs_->GetDictionary(prefs::kArcApps);
+  if (!apps || !apps->GetDictionary(app_id, &app))
+    return false;
+
+  return true;
+}
+
+void ArcAppListPrefs::DisableAllApps() {
+  for (auto& app_id : ready_apps_)
+    FOR_EACH_OBSERVER(Observer,
+                      observer_list_,
+                      OnAppReadyChanged(app_id, false));
+
+  ready_apps_.clear();
+}
+
+void ArcAppListPrefs::OnStateChanged(arc::ArcBridgeService::State state) {
+  if (state == arc::ArcBridgeService::State::READY)
+    arc::ArcBridgeService::Get()->RefreshAppList();
+  else
+    DisableAllApps();
+}
+
+void ArcAppListPrefs::OnAppReady(const arc::AppInfo& app) {
+  if (app.name.empty() || app.package.empty() || app.activity.empty()) {
+    VLOG(2) << "Name, package and activity cannot be empty.";
+    return;
+  }
+  std::string app_id = GetAppId(app.package, app.activity);
+  bool was_registered = IsRegistered(app_id);
+
+  ScopedArcAppListPrefUpdate update(prefs_, app_id);
+  base::DictionaryValue* app_dict = update.Get();
+  app_dict->SetString(kName, app.name);
+  app_dict->SetString(kPackage, app.package);
+  app_dict->SetString(kActivity, app.activity);
+
+  // From now, app is ready.
+  if (!ready_apps_.count(app_id))
+    ready_apps_.insert(app_id);
+
+  if (was_registered) {
+    FOR_EACH_OBSERVER(Observer,
+                      observer_list_,
+                      OnAppReadyChanged(app_id, true));
+  } else {
+    AppInfo app_info(app.name, app.package, app.activity, true);
+    FOR_EACH_OBSERVER(Observer,
+                      observer_list_,
+                      OnAppRegistered(app_id, app_info));
+  }
+
+  std::map<std::string, uint32>::iterator deferred_icons =
+      request_icon_deferred_.find(app_id);
+  if (deferred_icons != request_icon_deferred_.end()) {
+    for (uint32 i = ui::SCALE_FACTOR_100P; i < ui::NUM_SCALE_FACTORS; ++i) {
+      if (deferred_icons->second & (1 << i)) {
+         RequestIcon(app_id, static_cast<ui::ScaleFactor>(i));
+      }
+    }
+    request_icon_deferred_.erase(deferred_icons);
+  }
+}
+
+void ArcAppListPrefs::OnAppListRefreshed(
+    const std::vector<arc::AppInfo>& apps) {
+  std::set<std::string> old_ready_apps;
+  old_ready_apps.swap(ready_apps_);
+
+  for (auto& app : apps)
+    OnAppReady(app);
+
+  // Detect unavailable apps after current refresh.
+  for (auto& app_id : old_ready_apps) {
+    if (!ready_apps_.count(app_id)) {
+      FOR_EACH_OBSERVER(Observer,
+                        observer_list_,
+                        OnAppReadyChanged(app_id, false));
+    }
+  }
+}
+
+void ArcAppListPrefs::OnAppIcon(const std::string& package,
+                                const std::string& activity,
+                                arc::ScaleFactor scale_factor,
+                                const std::vector<uint8_t>& icon_png_data) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  DCHECK(!icon_png_data.empty());
+  DCHECK(scale_factor >= arc::SCALE_FACTOR_100P &&
+         scale_factor < arc::NUM_SCALE_FACTORS);
+
+  std::string app_id = GetAppId(package, activity);
+  if (!IsRegistered(app_id)) {
+    VLOG(2) << "Request to update icon for non-registered app: " << app_id;
+    return;
+  }
+
+  InstallIcon(app_id,
+              static_cast<ui::ScaleFactor>(scale_factor),
+              icon_png_data);
+}
+
+
+void ArcAppListPrefs::InstallIcon(const std::string& app_id,
+                                  ui::ScaleFactor scale_factor,
+                                  const std::vector<uint8>& content_png) {
+
+  base::FilePath icon_path = GetIconPath(app_id, scale_factor);
+  base::PostTaskAndReplyWithResult(content::BrowserThread::GetBlockingPool(),
+                                   FROM_HERE,
+                                   base::Bind(&InstallIconFromFileThread,
+                                              app_id,
+                                              scale_factor,
+                                              icon_path,
+                                              content_png),
+                                   base::Bind(&ArcAppListPrefs::OnIconInstalled,
+                                              weak_ptr_factory_.GetWeakPtr(),
+                                              app_id,
+                                              scale_factor));
+}
+
+void ArcAppListPrefs::OnIconInstalled(const std::string& app_id,
+                                      ui::ScaleFactor scale_factor,
+                                      bool install_succeed) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  if (!install_succeed)
+    return;
+
+  FOR_EACH_OBSERVER(Observer,
+                    observer_list_,
+                    OnAppIconUpdated(app_id, scale_factor));
+}
+
+ArcAppListPrefs::AppInfo::AppInfo(const std::string& name,
+                                  const std::string& package,
+                                  const std::string& activity,
+                                  bool ready)
+    : name(name),
+      package(package),
+      activity(activity),
+      ready(ready) {
+}
diff --git a/chrome/browser/ui/app_list/arc/arc_app_list_prefs.h b/chrome/browser/ui/app_list/arc/arc_app_list_prefs.h
new file mode 100644
index 0000000..a8e7bba
--- /dev/null
+++ b/chrome/browser/ui/app_list/arc/arc_app_list_prefs.h
@@ -0,0 +1,148 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_APP_LIST_ARC_ARC_APP_LIST_PREFS_H_
+#define CHROME_BROWSER_UI_APP_LIST_ARC_ARC_APP_LIST_PREFS_H_
+
+#include <map>
+#include <set>
+#include <vector>
+
+#include "base/files/file_path.h"
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "base/observer_list.h"
+#include "components/arc/arc_bridge_service.h"
+#include "components/keyed_service/core/keyed_service.h"
+#include "ui/base/layout.h"
+
+class PrefService;
+
+namespace content {
+class BrowserContext;
+}
+
+namespace user_prefs {
+class PrefRegistrySyncable;
+}
+
+// Declares shareable ARC app specific preferences, that keep information
+// about app attributes (name, package, activity) and its state. This
+// information is used to pre-create non-ready app items while ARC bridge
+// service is not ready to provide information about available ARC apps.
+class ArcAppListPrefs : public KeyedService,
+                        public arc::ArcBridgeService::Observer,
+                        public arc::ArcBridgeService::AppObserver {
+ public:
+  struct AppInfo {
+    AppInfo(const std::string& name,
+            const std::string& package,
+            const std::string& activity,
+            bool ready);
+
+    std::string name;
+    std::string package;
+    std::string activity;
+    bool ready;
+  };
+
+  class Observer {
+   public:
+    // Notifies an observer that new app is registered.
+    virtual void OnAppRegistered(const std::string& app_id,
+                                 const AppInfo& app_info) = 0;
+    // Notifies an observer that app ready state has been changed.
+    virtual void OnAppReadyChanged(const std::string& id, bool ready) = 0;
+    // Notifies an observer that app icon has been installed or updated.
+    virtual void OnAppIconUpdated(const std::string& id,
+                                  ui::ScaleFactor scale_factor) = 0;
+   protected:
+    virtual ~Observer() {}
+  };
+
+  static ArcAppListPrefs* Create(const base::FilePath& base_path,
+                                 PrefService* prefs);
+
+  // Convenience function to get the ArcAppListPrefs for a BrowserContext.
+  static ArcAppListPrefs* Get(content::BrowserContext* context);
+
+  // Constructs unique id based on package and activity information. This id
+  // is safe to use at file paths and as preference keys.
+  static std::string GetAppId(const std::string& package,
+                              const std::string& activity);
+
+  // It is called from chrome/browser/prefs/browser_prefs.cc.
+  static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
+
+  ~ArcAppListPrefs() override;
+
+  // Returns a list of all app ids, including ready and non-ready apps.
+  std::vector<std::string> GetAppIds() const;
+
+  // Extracts attributes of an app based on its id. Returns NULL if the app is
+  // not found.
+  scoped_ptr<AppInfo> GetApp(const std::string& app_id) const;
+
+  // Constructs path to app icon for specific scale factor.
+  base::FilePath GetIconPath(const std::string& app_id,
+                             ui::ScaleFactor scale_factor) const;
+
+  // Requests to load an app icon for specific scale factor. If the app or Arc
+  // bridge service is not ready, then defer this request until the app gets
+  // available. Once new icon is installed notifies an observer
+  // OnAppIconUpdated.
+  void RequestIcon(const std::string& app_id, ui::ScaleFactor scale_factor);
+
+  // Returns true if app is registered.
+  bool IsRegistered(const std::string& app_id);
+
+  void AddObserver(Observer* observer);
+  void RemoveObserver(Observer* observer);
+
+  // arc::ArcBridgeService::Observer
+  void OnStateChanged(arc::ArcBridgeService::State state) override;
+  void OnAppListRefreshed(const std::vector<arc::AppInfo>& apps) override;
+  void OnAppIcon(const std::string& package,
+                 const std::string& activity,
+                 arc::ScaleFactor scale_factor,
+                 const std::vector<uint8_t>& icon_png_data) override;
+
+ private:
+  // See the Create methods.
+  ArcAppListPrefs(const base::FilePath& base_path, PrefService* prefs);
+
+  void OnAppReady(const arc::AppInfo& app);
+  void DisableAllApps();
+
+  // Installs an icon to file system in the special folder of the profile
+  // directory.
+  void InstallIcon(const std::string& app_id,
+                   ui::ScaleFactor scale_factor,
+                   const std::vector<uint8>& contentPng);
+  void OnIconInstalled(const std::string& app_id,
+                       ui::ScaleFactor scale_factor,
+                       bool install_succeed);
+
+  // Owned by the BrowserContext.
+  PrefService* prefs_;
+
+  // List of observers.
+  base::ObserverList<Observer> observer_list_;
+  // Keeps root folder where ARC app icons for different scale factor are
+  // stored.
+  base::FilePath base_path_;
+  // Contains set of ARC apps that are currently ready.
+  std::set<std::string> ready_apps_;
+  // Keeps deferred icon load requests. Each app may contain several requests
+  // for different scale factor. Scale factor is defined by specific bit
+  // position.
+  std::map<std::string, uint32> request_icon_deferred_;
+
+  base::WeakPtrFactory<ArcAppListPrefs> weak_ptr_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(ArcAppListPrefs);
+};
+
+#endif  // CHROME_BROWSER_UI_APP_LIST_ARC_ARC_APP_LIST_PREFS_H_
diff --git a/chrome/browser/ui/app_list/arc/arc_app_list_prefs_factory.cc b/chrome/browser/ui/app_list/arc/arc_app_list_prefs_factory.cc
new file mode 100644
index 0000000..e6051ca3
--- /dev/null
+++ b/chrome/browser/ui/app_list/arc/arc_app_list_prefs_factory.cc
@@ -0,0 +1,45 @@
+// 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.
+
+#include "chrome/browser/ui/app_list/arc/arc_app_list_prefs_factory.h"
+
+#include "chrome/browser/profiles/incognito_helpers.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/app_list/arc/arc_app_list_prefs.h"
+#include "components/keyed_service/content/browser_context_dependency_manager.h"
+#include "content/public/browser/browser_context.h"
+
+// static
+ArcAppListPrefs* ArcAppListPrefsFactory::GetForBrowserContext(
+    content::BrowserContext* context) {
+  return static_cast<ArcAppListPrefs*>(
+      GetInstance()->GetServiceForBrowserContext(context, true));
+}
+
+// static
+ArcAppListPrefsFactory* ArcAppListPrefsFactory::GetInstance() {
+  return base::Singleton<ArcAppListPrefsFactory>::get();
+}
+
+ArcAppListPrefsFactory::ArcAppListPrefsFactory()
+    : BrowserContextKeyedServiceFactory(
+          "ArcAppListPrefs",
+          BrowserContextDependencyManager::GetInstance()) {
+}
+
+ArcAppListPrefsFactory::~ArcAppListPrefsFactory() {
+}
+
+KeyedService* ArcAppListPrefsFactory::BuildServiceInstanceFor(
+    content::BrowserContext* context) const {
+  Profile* profile = static_cast<Profile*>(context);
+  return ArcAppListPrefs::Create(profile->GetPath(), profile->GetPrefs());
+}
+
+content::BrowserContext* ArcAppListPrefsFactory::GetBrowserContextToUse(
+    content::BrowserContext* context) const {
+  // This matches the logic in ExtensionSyncServiceFactory, which uses the
+  // orginal browser context.
+  return chrome::GetBrowserContextRedirectedInIncognito(context);
+}
diff --git a/chrome/browser/ui/app_list/arc/arc_app_list_prefs_factory.h b/chrome/browser/ui/app_list/arc/arc_app_list_prefs_factory.h
new file mode 100644
index 0000000..e70773b
--- /dev/null
+++ b/chrome/browser/ui/app_list/arc/arc_app_list_prefs_factory.h
@@ -0,0 +1,36 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_APP_LIST_ARC_ARC_APP_LIST_PREFS_FACTORY_H_
+#define CHROME_BROWSER_UI_APP_LIST_ARC_ARC_APP_LIST_PREFS_FACTORY_H_
+
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/singleton.h"
+#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
+
+class ArcAppListPrefs;
+
+class ArcAppListPrefsFactory : public BrowserContextKeyedServiceFactory {
+ public:
+  static ArcAppListPrefs* GetForBrowserContext(
+      content::BrowserContext* context);
+
+  static ArcAppListPrefsFactory* GetInstance();
+
+ private:
+  friend struct base::DefaultSingletonTraits<ArcAppListPrefsFactory>;
+
+  ArcAppListPrefsFactory();
+  ~ArcAppListPrefsFactory() override;
+
+  KeyedService* BuildServiceInstanceFor(
+      content::BrowserContext* context) const override;
+  content::BrowserContext* GetBrowserContextToUse(
+      content::BrowserContext* context) const override;
+
+  DISALLOW_COPY_AND_ASSIGN(ArcAppListPrefsFactory);
+};
+
+#endif  // CHROME_BROWSER_UI_APP_LIST_ARC_ARC_APP_LIST_PREFS_FACTORY_H_
diff --git a/chrome/browser/ui/app_list/arc/arc_app_model_builder.cc b/chrome/browser/ui/app_list/arc/arc_app_model_builder.cc
new file mode 100644
index 0000000..445f935
--- /dev/null
+++ b/chrome/browser/ui/app_list/arc/arc_app_model_builder.cc
@@ -0,0 +1,84 @@
+// 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.
+
+#include "chrome/browser/ui/app_list/arc/arc_app_model_builder.h"
+
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/app_list/arc/arc_app_item.h"
+
+ArcAppModelBuilder::ArcAppModelBuilder(AppListControllerDelegate* controller)
+    : AppListModelBuilder(controller, ArcAppItem::kItemType) {
+}
+
+ArcAppModelBuilder::~ArcAppModelBuilder() {
+  prefs_->RemoveObserver(this);
+}
+
+void ArcAppModelBuilder::BuildModel() {
+  prefs_ = ArcAppListPrefs::Get(profile());
+
+  std::vector<std::string> app_ids = prefs_->GetAppIds();
+  for (auto& app_id : app_ids) {
+    scoped_ptr<ArcAppListPrefs::AppInfo> app_info = prefs_->GetApp(app_id);
+    if (!app_info)
+      continue;
+
+    InsertApp(CreateApp(app_id, *app_info));
+  }
+
+  prefs_->AddObserver(this);
+}
+
+ArcAppItem* ArcAppModelBuilder::GetArcAppItem(const std::string& app_id) {
+  return static_cast<ArcAppItem*>(GetAppItem(app_id));
+}
+
+scoped_ptr<ArcAppItem> ArcAppModelBuilder::CreateApp(
+    const std::string& app_id,
+    const ArcAppListPrefs::AppInfo& app_info) {
+  return make_scoped_ptr(new ArcAppItem(profile(),
+                                        GetSyncItem(app_id),
+                                        app_id,
+                                        app_info.name,
+                                        app_info.ready));
+}
+
+void ArcAppModelBuilder::OnAppRegistered(
+    const std::string& app_id,
+    const ArcAppListPrefs::AppInfo& app_info) {
+  InsertApp(CreateApp(app_id, app_info));
+}
+
+void ArcAppModelBuilder::OnAppReadyChanged(const std::string& app_id,
+                                           bool ready) {
+  ArcAppItem* app_item = GetArcAppItem(app_id);
+  if (!app_item) {
+    VLOG(2) << "Could not update the state of ARC app(" << app_id
+            << ") because it was not found.";
+    return;
+  }
+
+  app_item->SetReady(ready);
+}
+
+void ArcAppModelBuilder::OnAppIconUpdated(const std::string& app_id,
+                                          ui::ScaleFactor scale_factor) {
+  ArcAppItem* app_item = GetArcAppItem(app_id);
+  if (!app_item) {
+    VLOG(2) << "Could not update the icon of ARC app(" << app_id
+            << ") because it was not found.";
+    return;
+  }
+
+  // Initiate async icon reloading.
+  app_item->arc_app_icon()->LoadForScaleFactor(scale_factor);
+}
+
+void ArcAppModelBuilder::OnListItemMoved(size_t from_index,
+                                         size_t to_index,
+                                         app_list::AppListItem* item) {
+  // On ChromeOS we expect that ArcAppModelBuilder is initialized with
+  // AppListSyncableService and in this case this observer is not used.
+  NOTREACHED();
+}
diff --git a/chrome/browser/ui/app_list/arc/arc_app_model_builder.h b/chrome/browser/ui/app_list/arc/arc_app_model_builder.h
new file mode 100644
index 0000000..04439c7
--- /dev/null
+++ b/chrome/browser/ui/app_list/arc/arc_app_model_builder.h
@@ -0,0 +1,51 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_APP_LIST_ARC_ARC_APP_MODEL_BUILDER_H_
+#define CHROME_BROWSER_UI_APP_LIST_ARC_ARC_APP_MODEL_BUILDER_H_
+
+#include <string>
+
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "chrome/browser/ui/app_list/app_list_model_builder.h"
+#include "chrome/browser/ui/app_list/arc/arc_app_list_prefs.h"
+
+class AppListControllerDelegate;
+class ArcAppItem;
+
+// This class populates and maintains ARC apps.
+class ArcAppModelBuilder : public AppListModelBuilder,
+                           public ArcAppListPrefs::Observer {
+ public:
+  explicit ArcAppModelBuilder(AppListControllerDelegate* controller);
+  ~ArcAppModelBuilder() override;
+
+ private:
+  // AppListModelBuilder
+  void BuildModel() override;
+
+  // ArcAppListPrefs::Observer
+  void OnAppRegistered(const std::string& app_id,
+                       const ArcAppListPrefs::AppInfo& app_info) override;
+  void OnAppReadyChanged(const std::string& app_id, bool ready) override;
+  void OnAppIconUpdated(const std::string& app_id,
+                        ui::ScaleFactor scale_factor) override;
+
+  // AppListItemListObserver.
+  void OnListItemMoved(size_t from_index,
+                       size_t to_index,
+                       app_list::AppListItem* item) override;
+
+  scoped_ptr<ArcAppItem> CreateApp(const std::string& app_id,
+                                   const ArcAppListPrefs::AppInfo& info);
+
+  ArcAppItem* GetArcAppItem(const std::string& app_id);
+
+  ArcAppListPrefs* prefs_ = nullptr;
+
+  DISALLOW_COPY_AND_ASSIGN(ArcAppModelBuilder);
+};
+
+#endif  // CHROME_BROWSER_UI_APP_LIST_ARC_ARC_APP_MODEL_BUILDER_H_
diff --git a/chrome/browser/ui/app_list/arc/arc_app_unittest.cc b/chrome/browser/ui/app_list/arc/arc_app_unittest.cc
new file mode 100644
index 0000000..df39fe6
--- /dev/null
+++ b/chrome/browser/ui/app_list/arc/arc_app_unittest.cc
@@ -0,0 +1,399 @@
+// 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.
+
+#include <algorithm>
+#include <map>
+#include <string>
+#include <vector>
+
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/memory/scoped_vector.h"
+#include "base/run_loop.h"
+#include "base/strings/string_util.h"
+#include "base/task_runner_util.h"
+#include "chrome/browser/ui/app_list/app_list_test_util.h"
+#include "chrome/browser/ui/app_list/arc/arc_app_icon.h"
+#include "chrome/browser/ui/app_list/arc/arc_app_item.h"
+#include "chrome/browser/ui/app_list/arc/arc_app_list_prefs.h"
+#include "chrome/browser/ui/app_list/arc/arc_app_model_builder.h"
+#include "chrome/browser/ui/app_list/test/test_app_list_controller_delegate.h"
+#include "chrome/test/base/testing_profile.h"
+#include "components/arc/arc_bridge_service.h"
+#include "components/arc/test/fake_arc_bridge_service.h"
+#include "content/public/browser/browser_thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/app_list/app_list_model.h"
+#include "ui/gfx/image/image_skia.h"
+
+namespace {
+
+std::string GetAppId(const arc::AppInfo& app_info) {
+  return ArcAppListPrefs::GetAppId(app_info.package, app_info.activity);
+}
+
+}  // namespace
+
+class ArcAppModelBuilderTest : public AppListTestBase {
+ public:
+  ArcAppModelBuilderTest() {}
+  ~ArcAppModelBuilderTest() override {
+    // Release profile file in order to keep right sequence.
+    profile_.reset();
+  }
+
+  void SetUp() override {
+    AppListTestBase::SetUp();
+
+    // Make sure we have enough data for test.
+    for (int i = 0; i < 3; ++i) {
+      arc::AppInfo app;
+      char buffer[16];
+      base::snprintf(buffer, arraysize(buffer), "Fake App %d", i);
+      app.name = buffer;
+      base::snprintf(buffer, arraysize(buffer), "fake.app.%d", i);
+      app.package = buffer;
+      base::snprintf(buffer, arraysize(buffer), "fake.app.%d.activity", i);
+      app.activity = buffer;
+      fake_apps_.push_back(app);
+    }
+
+    bridge_service_.reset(new arc::FakeArcBridgeService());
+
+    // Check initial conditions.
+    EXPECT_EQ(bridge_service_.get(), arc::ArcBridgeService::Get());
+    EXPECT_EQ(true, !arc::ArcBridgeService::Get()->available());
+    EXPECT_EQ(arc::ArcBridgeService::State::STOPPED,
+              arc::ArcBridgeService::Get()->state());
+
+    CreateBuilder();
+
+    // At this point we should have ArcAppListPrefs as observer of service.
+    EXPECT_EQ(
+        true,
+        bridge_service()->HasObserver(ArcAppListPrefs::Get(profile_.get())));
+  }
+
+  void TearDown() override { ResetBuilder(); }
+
+ protected:
+  // Creates a new builder, destroying any existing one.
+  void CreateBuilder() {
+    ResetBuilder();  // Destroy any existing builder in the correct order.
+
+    model_.reset(new app_list::AppListModel);
+    controller_.reset(new test::TestAppListControllerDelegate);
+    builder_.reset(new ArcAppModelBuilder(controller_.get()));
+    builder_->InitializeWithProfile(profile_.get(), model_.get());
+  }
+
+  void ResetBuilder() {
+    builder_.reset();
+    controller_.reset();
+    model_.reset();
+  }
+
+  size_t GetArcItemCount() const {
+    size_t arc_count = 0;
+    const size_t count = model_->top_level_item_list()->item_count();
+    for (size_t i = 0; i < count; ++i) {
+      app_list::AppListItem* item = model_->top_level_item_list()->item_at(i);
+      if (item->GetItemType() == ArcAppItem::kItemType)
+        ++arc_count;
+    }
+    return arc_count;
+  }
+
+  ArcAppItem* GetArcItem(size_t index) const {
+    size_t arc_count = 0;
+    const size_t count = model_->top_level_item_list()->item_count();
+    ArcAppItem* arc_item = nullptr;
+    for (size_t i = 0; i < count; ++i) {
+      app_list::AppListItem* item = model_->top_level_item_list()->item_at(i);
+      if (item->GetItemType() == ArcAppItem::kItemType) {
+        if (arc_count++ == index) {
+          arc_item = reinterpret_cast<ArcAppItem*>(item);
+          break;
+        }
+      }
+    }
+    EXPECT_NE(nullptr, arc_item);
+    return arc_item;
+  }
+
+  ArcAppItem* FindArcItem(const std::string& id) const {
+    const size_t count = GetArcItemCount();
+    for (size_t i = 0; i < count; ++i) {
+      ArcAppItem* item = GetArcItem(i);
+      if (item && item->id() == id)
+        return item;
+    }
+    return nullptr;
+  }
+
+  // Validate that prefs and model have right content.
+  void ValidateHaveApps(const std::vector<arc::AppInfo> apps) {
+    ArcAppListPrefs* prefs = ArcAppListPrefs::Get(profile_.get());
+    const std::vector<std::string> ids = prefs->GetAppIds();
+    ASSERT_EQ(apps.size(), ids.size());
+    ASSERT_EQ(apps.size(), GetArcItemCount());
+    // In principle, order of items is not defined.
+    for (auto& app : apps) {
+      const std::string id = GetAppId(app);
+      EXPECT_NE(std::find(ids.begin(), ids.end(), id), ids.end());
+      scoped_ptr<ArcAppListPrefs::AppInfo> app_info = prefs->GetApp(id);
+      ASSERT_NE(nullptr, app_info.get());
+      EXPECT_EQ(app.name, app_info->name);
+      EXPECT_EQ(app.package, app_info->package);
+      EXPECT_EQ(app.activity, app_info->activity);
+
+      const ArcAppItem* app_item = FindArcItem(id);
+      ASSERT_NE(nullptr, app_item);
+      EXPECT_EQ(app.name, app_item->GetDisplayName());
+    }
+  }
+
+  // Validate that requested apps have required ready state and other apps have
+  // opposite state.
+  void ValidateAppReadyState(const std::vector<arc::AppInfo> apps, bool ready) {
+    ArcAppListPrefs* prefs = ArcAppListPrefs::Get(profile_.get());
+    ASSERT_NE(nullptr, prefs);
+
+    std::vector<std::string> ids = prefs->GetAppIds();
+    EXPECT_EQ(ids.size(), GetArcItemCount());
+
+    // Process requested apps.
+    for (auto& app : apps) {
+      const std::string id = GetAppId(app);
+      std::vector<std::string>::iterator it_id = std::find(ids.begin(),
+                                                           ids.end(),
+                                                           id);
+      ASSERT_NE(it_id, ids.end());
+      ids.erase(it_id);
+
+      scoped_ptr<ArcAppListPrefs::AppInfo> app_info = prefs->GetApp(id);
+      ASSERT_NE(nullptr, app_info.get());
+      EXPECT_EQ(ready, app_info->ready);
+      const ArcAppItem* app_item = FindArcItem(id);
+      ASSERT_NE(nullptr, app_item);
+      EXPECT_EQ(ready, app_item->ready());
+    }
+
+    // Process the rest of the apps.
+    for (auto& id : ids) {
+      scoped_ptr<ArcAppListPrefs::AppInfo> app_info = prefs->GetApp(id);
+      ASSERT_NE(nullptr, app_info.get());
+      EXPECT_NE(ready, app_info->ready);
+      const ArcAppItem* app_item = FindArcItem(id);
+      ASSERT_NE(nullptr, app_item);
+      EXPECT_NE(ready, app_item->ready());
+    }
+
+  }
+
+  arc::FakeArcBridgeService* bridge_service() { return bridge_service_.get(); }
+
+  const std::vector<arc::AppInfo>& fake_apps() const { return fake_apps_; }
+
+ private:
+  scoped_ptr<app_list::AppListModel> model_;
+  scoped_ptr<test::TestAppListControllerDelegate> controller_;
+  scoped_ptr<ArcAppModelBuilder> builder_;
+  scoped_ptr<arc::FakeArcBridgeService> bridge_service_;
+  std::vector<arc::AppInfo> fake_apps_;
+
+  DISALLOW_COPY_AND_ASSIGN(ArcAppModelBuilderTest);
+};
+
+TEST_F(ArcAppModelBuilderTest, RefreshAllOnReady) {
+  EXPECT_EQ(0, bridge_service()->refresh_app_list_count());
+  bridge_service()->SetReady();
+  EXPECT_EQ(1, bridge_service()->refresh_app_list_count());
+}
+
+TEST_F(ArcAppModelBuilderTest, RefreshAllFillsContent) {
+  ValidateHaveApps(std::vector<arc::AppInfo>());
+  bridge_service()->SetReady();
+  bridge_service()->SendRefreshAppList(fake_apps());
+  ValidateHaveApps(fake_apps());
+}
+
+TEST_F(ArcAppModelBuilderTest, MultipleRefreshAll) {
+  ValidateHaveApps(std::vector<arc::AppInfo>());
+  bridge_service()->SetReady();
+  // Send info about all fake apps except last.
+  std::vector<arc::AppInfo> apps1(fake_apps().begin(), fake_apps().end() - 1);
+  bridge_service()->SendRefreshAppList(apps1);
+  // At this point all apps (except last) should exist and be ready.
+  ValidateHaveApps(apps1);
+  ValidateAppReadyState(apps1, true);
+
+  // Send info about all fake apps except first.
+  std::vector<arc::AppInfo> apps2(fake_apps().begin() + 1, fake_apps().end());
+  bridge_service()->SendRefreshAppList(apps2);
+  // At this point all apps should exist but first one should be non-ready.
+  ValidateHaveApps(fake_apps());
+  ValidateAppReadyState(apps2, true);
+
+  // Send info about all fake apps.
+  bridge_service()->SendRefreshAppList(fake_apps());
+  // At this point all apps should exist and be ready.
+  ValidateHaveApps(fake_apps());
+  ValidateAppReadyState(fake_apps(), true);
+
+  // Send info no app available.
+  bridge_service()->SendRefreshAppList(std::vector<arc::AppInfo>());
+  // At this point all apps should exist and be non-ready.
+  ValidateHaveApps(fake_apps());
+  ValidateAppReadyState(fake_apps(), false);
+}
+
+TEST_F(ArcAppModelBuilderTest, StopServiceDisablesApps) {
+  ArcAppListPrefs* prefs = ArcAppListPrefs::Get(profile_.get());
+  ASSERT_NE(nullptr, prefs);
+
+  bridge_service()->SetReady();
+  EXPECT_EQ(static_cast<size_t>(0), GetArcItemCount());
+  EXPECT_EQ(static_cast<size_t>(0), prefs->GetAppIds().size());
+
+  bridge_service()->SendRefreshAppList(fake_apps());
+  std::vector<std::string> ids = prefs->GetAppIds();
+  EXPECT_EQ(fake_apps().size(), ids.size());
+  ValidateAppReadyState(fake_apps(), true);
+
+  // Stopping service does not delete items. It makes them non-ready.
+  bridge_service()->SetStopped();
+  // Ids should be the same.
+  EXPECT_EQ(ids, prefs->GetAppIds());
+  ValidateAppReadyState(fake_apps(), false);
+}
+
+TEST_F(ArcAppModelBuilderTest, LaunchApps) {
+  bridge_service()->SetReady();
+  bridge_service()->SendRefreshAppList(fake_apps());
+
+  // Simulate item activate.
+  const arc::AppInfo& app_first = fake_apps()[0];
+  const arc::AppInfo& app_last = fake_apps()[0];
+  ArcAppItem* item_first = FindArcItem(GetAppId(app_first));
+  ArcAppItem* item_last = FindArcItem(GetAppId(app_last));
+  ASSERT_NE(nullptr, item_first);
+  ASSERT_NE(nullptr, item_last);
+  item_first->Activate(0);
+  item_last->Activate(0);
+  item_first->Activate(0);
+
+  const ScopedVector<arc::FakeArcBridgeService::Request>& launch_requests =
+      bridge_service()->launch_requests();
+  EXPECT_EQ(static_cast<size_t>(3), launch_requests.size());
+  EXPECT_EQ(true, launch_requests[0]->IsForApp(app_first));
+  EXPECT_EQ(true, launch_requests[1]->IsForApp(app_last));
+  EXPECT_EQ(true, launch_requests[2]->IsForApp(app_first));
+}
+
+TEST_F(ArcAppModelBuilderTest, RequestIcons) {
+  // Make sure we are on UI thread.
+  ASSERT_EQ(true,
+            content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+
+  bridge_service()->SetReady();
+  bridge_service()->SendRefreshAppList(fake_apps());
+
+  // Validate that no icon exists at the beginning and request icon for
+  // each supported scale factor. This will start asynchronous loading.
+  uint32_t expected_mask = 0;
+  const std::vector<ui::ScaleFactor>& scale_factors =
+      ui::GetSupportedScaleFactors();
+  for (auto& scale_factor : scale_factors) {
+    expected_mask |= 1 <<  scale_factor;
+    for (auto& app : fake_apps()) {
+      ArcAppItem* app_item = FindArcItem(GetAppId(app));
+      ASSERT_NE(nullptr, app_item);
+      const float scale = ui::GetScaleForScaleFactor(scale_factor);
+      app_item->icon().GetRepresentation(scale);
+    }
+  }
+
+  // Process pending tasks.
+  content::BrowserThread::GetBlockingPool()->FlushForTesting();
+  base::RunLoop().RunUntilIdle();
+
+  // At this moment we should receive all requests for icon loading.
+  const ScopedVector<arc::FakeArcBridgeService::IconRequest>& icon_requests =
+      bridge_service()->icon_requests();
+  EXPECT_EQ(scale_factors.size() * fake_apps().size(), icon_requests.size());
+  std::map<std::string, uint32_t> app_masks;
+  for (size_t i = 0; i < icon_requests.size(); ++i) {
+    const arc::FakeArcBridgeService::IconRequest* icon_request =
+        icon_requests[i];
+    const std::string id = ArcAppListPrefs::GetAppId(icon_request->package(),
+                                                     icon_request->activity());
+    // Make sure no double requests.
+    EXPECT_NE(app_masks[id],
+              app_masks[id] | (1 << icon_request->scale_factor()));
+    app_masks[id] |= (1 << icon_request->scale_factor());
+  }
+
+  // Validate that we have a request for each icon for each supported scale
+  // factor.
+  EXPECT_EQ(fake_apps().size(), app_masks.size());
+  for (auto& app : fake_apps()) {
+    const std::string id = GetAppId(app);
+    ASSERT_NE(app_masks.find(id), app_masks.end());
+    EXPECT_EQ(app_masks[id], expected_mask);
+  }
+}
+
+TEST_F(ArcAppModelBuilderTest, InstallIcon) {
+  // Make sure we are on UI thread.
+  ASSERT_EQ(true,
+            content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+
+
+  bridge_service()->SetReady();
+  bridge_service()->SendRefreshAppList(std::vector<arc::AppInfo>(
+      fake_apps().begin(), fake_apps().begin() + 1));
+  const arc::AppInfo& app = fake_apps()[0];
+
+  ArcAppListPrefs* prefs = ArcAppListPrefs::Get(profile_.get());
+  ASSERT_NE(nullptr, prefs);
+
+  const ui::ScaleFactor scale_factor = ui::GetSupportedScaleFactors()[0];
+  const float scale = ui::GetScaleForScaleFactor(scale_factor);
+  const base::FilePath icon_path = prefs->GetIconPath(GetAppId(app),
+                                                      scale_factor);
+  EXPECT_EQ(true, !base::PathExists(icon_path));
+
+  const ArcAppItem* app_item = FindArcItem(GetAppId(app));
+  EXPECT_NE(nullptr, app_item);
+  // This initiates async loading.
+  app_item->icon().GetRepresentation(scale);
+
+  // Process pending tasks.
+  content::BrowserThread::GetBlockingPool()->FlushForTesting();
+  base::RunLoop().RunUntilIdle();
+
+  // Validating decoded content does not fit well for unit tests.
+  ArcAppIcon::DisableDecodingForTesting();
+
+  // Now send generated icon for the app.
+  std::string png_data;
+  EXPECT_EQ(true, bridge_service()->GenerateAndSendIcon(
+      app,
+      static_cast<arc::ScaleFactor>(scale_factor),
+      &png_data));
+
+  // Process pending tasks.
+  content::BrowserThread::GetBlockingPool()->FlushForTesting();
+  base::RunLoop().RunUntilIdle();
+
+  // Validate that icons are installed, have right content and icon is
+  // refreshed for ARC app item.
+  EXPECT_EQ(true, base::PathExists(icon_path));
+
+  std::string icon_data;
+  // Read the file from disk and compare with reference data.
+  EXPECT_EQ(true, base::ReadFileToString(icon_path, &icon_data));
+  ASSERT_EQ(icon_data, png_data);
+}
diff --git a/chrome/browser/ui/app_list/extension_app_model_builder.cc b/chrome/browser/ui/app_list/extension_app_model_builder.cc
index ec4c287..2956f97 100644
--- a/chrome/browser/ui/app_list/extension_app_model_builder.cc
+++ b/chrome/browser/ui/app_list/extension_app_model_builder.cc
@@ -12,11 +12,9 @@
 #include "chrome/browser/extensions/extension_ui_util.h"
 #include "chrome/browser/extensions/extension_util.h"
 #include "chrome/browser/extensions/install_tracker.h"
-#include "chrome/browser/extensions/install_tracker_factory.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/app_list/app_list_controller_delegate.h"
 #include "chrome/browser/ui/app_list/app_list_syncable_service.h"
-#include "chrome/browser/ui/app_list/app_list_syncable_service_factory.h"
 #include "chrome/browser/ui/app_list/extension_app_item.h"
 #include "chrome/common/pref_names.h"
 #include "extensions/browser/extension_prefs.h"
@@ -34,47 +32,16 @@
 
 ExtensionAppModelBuilder::ExtensionAppModelBuilder(
     AppListControllerDelegate* controller)
-    : service_(NULL),
-      profile_(NULL),
-      controller_(controller),
-      model_(NULL),
-      tracker_(NULL),
-      extension_registry_(NULL) {
+    : AppListModelBuilder(controller, ExtensionAppItem::kItemType) {
 }
 
 ExtensionAppModelBuilder::~ExtensionAppModelBuilder() {
   OnShutdown();
   OnShutdown(extension_registry_);
-  if (!service_)
-    model_->top_level_item_list()->RemoveObserver(this);
-}
-
-void ExtensionAppModelBuilder::InitializeWithService(
-    app_list::AppListSyncableService* service,
-    app_list::AppListModel* model) {
-  DCHECK(!service_ && !profile_);
-  model_ = model;
-  service_ = service;
-  profile_ = service->profile();
-  InitializePrefChangeRegistrars();
-
-  BuildModel();
-}
-
-void ExtensionAppModelBuilder::InitializeWithProfile(
-    Profile* profile,
-    app_list::AppListModel* model) {
-  DCHECK(!service_ && !profile_);
-  model_ = model;
-  model_->top_level_item_list()->AddObserver(this);
-  profile_ = profile;
-  InitializePrefChangeRegistrars();
-
-  BuildModel();
 }
 
 void ExtensionAppModelBuilder::InitializePrefChangeRegistrars() {
-  profile_pref_change_registrar_.Init(profile_->GetPrefs());
+  profile_pref_change_registrar_.Init(profile()->GetPrefs());
   profile_pref_change_registrar_.Add(
       prefs::kHideWebStoreIcon,
       base::Bind(&ExtensionAppModelBuilder::OnProfilePreferenceChanged,
@@ -88,7 +55,7 @@
   extensions::ExtensionsBrowserClient* client =
       extensions::ExtensionsBrowserClient::Get();
   extension_pref_change_registrar_.Init(
-      client->GetPrefServiceForContext(profile_));
+      client->GetPrefServiceForContext(profile()));
   extension_pref_change_registrar_.Add(
     extensions::pref_names::kExtensions,
     base::Bind(&ExtensionAppModelBuilder::OnExtensionPreferenceChanged,
@@ -97,13 +64,13 @@
 
 void ExtensionAppModelBuilder::OnProfilePreferenceChanged() {
   extensions::ExtensionSet extensions;
-  controller_->GetApps(profile_, &extensions);
+  controller()->GetApps(profile(), &extensions);
 
   for (extensions::ExtensionSet::const_iterator app = extensions.begin();
        app != extensions.end(); ++app) {
     bool should_display =
-        extensions::ui_util::ShouldDisplayInAppLauncher(app->get(), profile_);
-    bool does_display = GetExtensionAppItem((*app)->id()) != NULL;
+        extensions::ui_util::ShouldDisplayInAppLauncher(app->get(), profile());
+    bool does_display = GetExtensionAppItem((*app)->id()) != nullptr;
 
     if (should_display == does_display)
       continue;
@@ -114,16 +81,16 @@
                               gfx::ImageSkia(),
                               (*app)->is_platform_app()));
     } else {
-      if (service_)
-        service_->RemoveItem((*app)->id());
+      if (service())
+        service()->RemoveItem((*app)->id());
       else
-        model_->DeleteItem((*app)->id());
+        model()->DeleteItem((*app)->id());
     }
   }
 }
 
 void ExtensionAppModelBuilder::OnExtensionPreferenceChanged() {
-  model_->NotifyExtensionPreferenceChanged();
+  model()->NotifyExtensionPreferenceChanged();
 }
 
 void ExtensionAppModelBuilder::OnBeginExtensionInstall(
@@ -131,7 +98,7 @@
   if (!params.is_app)
     return;
 
-  DVLOG(2) << service_ << ": OnBeginExtensionInstall: "
+  DVLOG(2) << service() << ": OnBeginExtensionInstall: "
            << params.extension_id.substr(0, 8);
   ExtensionAppItem* existing_item = GetExtensionAppItem(params.extension_id);
   if (existing_item) {
@@ -164,22 +131,22 @@
 
 void ExtensionAppModelBuilder::OnInstallFailure(
     const std::string& extension_id) {
-  model_->DeleteItem(extension_id);
+  model()->DeleteItem(extension_id);
 }
 
 void ExtensionAppModelBuilder::OnExtensionLoaded(
     content::BrowserContext* browser_context,
     const extensions::Extension* extension) {
-  if (!extensions::ui_util::ShouldDisplayInAppLauncher(extension, profile_))
+  if (!extensions::ui_util::ShouldDisplayInAppLauncher(extension, profile()))
     return;
 
-  DVLOG(2) << service_ << ": OnExtensionLoaded: "
+  DVLOG(2) << service() << ": OnExtensionLoaded: "
            << extension->id().substr(0, 8);
   ExtensionAppItem* existing_item = GetExtensionAppItem(extension->id());
   if (existing_item) {
     existing_item->Reload();
-    if (service_)
-      service_->UpdateItem(existing_item);
+    if (service())
+      service()->UpdateItem(existing_item);
     return;
   }
 
@@ -203,18 +170,18 @@
     content::BrowserContext* browser_context,
     const extensions::Extension* extension,
     extensions::UninstallReason reason) {
-  if (service_) {
-    DVLOG(2) << service_ << ": OnExtensionUninstalled: "
+  if (service()) {
+    DVLOG(2) << service() << ": OnExtensionUninstalled: "
              << extension->id().substr(0, 8);
-    service_->RemoveUninstalledItem(extension->id());
+    service()->RemoveUninstalledItem(extension->id());
     return;
   }
-  model_->DeleteUninstalledItem(extension->id());
+  model()->DeleteUninstalledItem(extension->id());
 }
 
 void ExtensionAppModelBuilder::OnDisabledExtensionUpdated(
     const Extension* extension) {
-  if (!extensions::ui_util::ShouldDisplayInAppLauncher(extension, profile_))
+  if (!extensions::ui_util::ShouldDisplayInAppLauncher(extension, profile()))
     return;
 
   ExtensionAppItem* existing_item = GetExtensionAppItem(extension->id());
@@ -225,7 +192,7 @@
 void ExtensionAppModelBuilder::OnShutdown() {
   if (tracker_) {
     tracker_->RemoveObserver(this);
-    tracker_ = NULL;
+    tracker_ = nullptr;
   }
 }
 
@@ -236,7 +203,7 @@
 
   DCHECK_EQ(extension_registry_, registry);
   extension_registry_->RemoveObserver(this);
-  extension_registry_ = NULL;
+  extension_registry_ = nullptr;
 }
 
 scoped_ptr<ExtensionAppItem> ExtensionAppModelBuilder::CreateAppItem(
@@ -244,10 +211,8 @@
     const std::string& extension_name,
     const gfx::ImageSkia& installing_icon,
     bool is_platform_app) {
-  const app_list::AppListSyncableService::SyncItem* sync_item =
-      service_ ? service_->GetSyncItem(extension_id) : NULL;
-  return make_scoped_ptr(new ExtensionAppItem(profile_,
-                                              sync_item,
+  return make_scoped_ptr(new ExtensionAppItem(profile(),
+                                              GetSyncItem(extension_id),
                                               extension_id,
                                               extension_name,
                                               installing_icon,
@@ -256,8 +221,11 @@
 
 void ExtensionAppModelBuilder::BuildModel() {
   DCHECK(!tracker_);
-  tracker_ = controller_->GetInstallTrackerFor(profile_);
-  extension_registry_ = extensions::ExtensionRegistry::Get(profile_);
+
+  InitializePrefChangeRegistrars();
+
+  tracker_ = controller()->GetInstallTrackerFor(profile());
+  extension_registry_ = extensions::ExtensionRegistry::Get(profile());
 
   PopulateApps();
 
@@ -271,11 +239,11 @@
 
 void ExtensionAppModelBuilder::PopulateApps() {
   extensions::ExtensionSet extensions;
-  controller_->GetApps(profile_, &extensions);
+  controller()->GetApps(profile(), &extensions);
 
   for (extensions::ExtensionSet::const_iterator app = extensions.begin();
        app != extensions.end(); ++app) {
-    if (!extensions::ui_util::ShouldDisplayInAppLauncher(app->get(), profile_))
+    if (!extensions::ui_util::ShouldDisplayInAppLauncher(app->get(), profile()))
       continue;
     InsertApp(CreateAppItem((*app)->id(),
                             "",
@@ -284,36 +252,23 @@
   }
 }
 
-void ExtensionAppModelBuilder::InsertApp(scoped_ptr<ExtensionAppItem> app) {
-  if (service_) {
-    service_->AddItem(app.Pass());
-    return;
-  }
-  model_->AddItem(app.Pass());
-}
-
 ExtensionAppItem* ExtensionAppModelBuilder::GetExtensionAppItem(
     const std::string& extension_id) {
-  app_list::AppListItem* item = model_->FindItem(extension_id);
-  LOG_IF(ERROR, item &&
-         item->GetItemType() != ExtensionAppItem::kItemType)
-      << "App Item matching id: " << extension_id
-      << " has incorrect type: '" << item->GetItemType() << "'";
-  return static_cast<ExtensionAppItem*>(item);
+  return static_cast<ExtensionAppItem*>(GetAppItem(extension_id));
 }
 
 void ExtensionAppModelBuilder::OnListItemMoved(size_t from_index,
                                                size_t to_index,
                                                app_list::AppListItem* item) {
-  DCHECK(!service_);
+  DCHECK(!service());
 
   // This will get called from AppListItemList::ListItemMoved after
   // set_position is called for the item.
   if (item->GetItemType() != ExtensionAppItem::kItemType)
     return;
 
-  app_list::AppListItemList* item_list = model_->top_level_item_list();
-  ExtensionAppItem* prev = NULL;
+  app_list::AppListItemList* item_list = model()->top_level_item_list();
+  ExtensionAppItem* prev = nullptr;
   for (size_t idx = to_index; idx > 0; --idx) {
     app_list::AppListItem* item = item_list->item_at(idx - 1);
     if (item->GetItemType() == ExtensionAppItem::kItemType) {
@@ -321,7 +276,7 @@
       break;
     }
   }
-  ExtensionAppItem* next = NULL;
+  ExtensionAppItem* next = nullptr;
   for (size_t idx = to_index; idx < item_list->item_count() - 1; ++idx) {
     app_list::AppListItem* item = item_list->item_at(idx + 1);
     if (item->GetItemType() == ExtensionAppItem::kItemType) {
diff --git a/chrome/browser/ui/app_list/extension_app_model_builder.h b/chrome/browser/ui/app_list/extension_app_model_builder.h
index 8b327e2..9303e38 100644
--- a/chrome/browser/ui/app_list/extension_app_model_builder.h
+++ b/chrome/browser/ui/app_list/extension_app_model_builder.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -9,19 +9,13 @@
 #include <vector>
 
 #include "base/prefs/pref_change_registrar.h"
-#include "base/scoped_observer.h"
 #include "chrome/browser/extensions/install_observer.h"
+#include "chrome/browser/ui/app_list/app_list_model_builder.h"
 #include "extensions/browser/extension_registry_observer.h"
-#include "ui/app_list/app_list_model.h"
 #include "ui/base/models/list_model_observer.h"
 
 class AppListControllerDelegate;
 class ExtensionAppItem;
-class Profile;
-
-namespace app_list {
-class AppListSyncableService;
-}
 
 namespace extensions {
 class Extension;
@@ -34,28 +28,20 @@
 class ImageSkia;
 }
 
-// This class populates and maintains the given |model| with information from
-// |profile|.
-class ExtensionAppModelBuilder : public extensions::InstallObserver,
-                                 public extensions::ExtensionRegistryObserver,
-                                 public app_list::AppListItemListObserver {
+// This class populates and maintains the given |model| for extension items
+// with information from |profile|.
+class ExtensionAppModelBuilder : public AppListModelBuilder,
+                                 public extensions::InstallObserver,
+                                 public extensions::ExtensionRegistryObserver {
  public:
   explicit ExtensionAppModelBuilder(AppListControllerDelegate* controller);
   ~ExtensionAppModelBuilder() override;
 
-  // Initialize to use app-list sync and sets |service_| to |service|.
-  void InitializeWithService(app_list::AppListSyncableService* service,
-                             app_list::AppListModel* model);
-
-  // Initialize to use extension sync and sets |service_| to NULL. Used in
-  // tests and when AppList sync is not enabled.
-  void InitializeWithProfile(Profile* profile, app_list::AppListModel* model);
-
  private:
   typedef std::vector<ExtensionAppItem*> ExtensionAppList;
 
-  // Builds the model with the current profile.
-  void BuildModel();
+  // AppListModelBuilder
+  void BuildModel() override;
 
   // extensions::InstallObserver.
   void OnBeginExtensionInstall(const ExtensionInstallParams& params) override;
@@ -92,9 +78,6 @@
   // Populates the model with apps.
   void PopulateApps();
 
-  // Inserts an app based on app ordinal prefs.
-  void InsertApp(scoped_ptr<ExtensionAppItem> app);
-
   // Returns app instance matching |extension_id| or NULL.
   ExtensionAppItem* GetExtensionAppItem(const std::string& extension_id);
 
@@ -110,27 +93,17 @@
   // Handles extension prefs changes.
   void OnExtensionPreferenceChanged();
 
-  // Unowned pointers to the service that owns this and associated profile.
-  app_list::AppListSyncableService* service_;
-  Profile* profile_;
-
   // Registrar used to monitor the profile prefs.
   PrefChangeRegistrar profile_pref_change_registrar_;
 
   // Registrar used to monitor the extension prefs.
   PrefChangeRegistrar extension_pref_change_registrar_;
 
-  // Unowned pointer to the app list controller.
-  AppListControllerDelegate* controller_;
-
-  // Unowned pointer to the app list model.
-  app_list::AppListModel* model_;
-
   // We listen to this to show app installing progress.
-  extensions::InstallTracker* tracker_;
+  extensions::InstallTracker* tracker_ = nullptr;
 
   // Listen extension's load, unload, uninstalled.
-  extensions::ExtensionRegistry* extension_registry_;
+  extensions::ExtensionRegistry* extension_registry_ = nullptr;
 
   DISALLOW_COPY_AND_ASSIGN(ExtensionAppModelBuilder);
 };
diff --git a/chrome/browser/ui/autofill/chrome_autofill_client.cc b/chrome/browser/ui/autofill/chrome_autofill_client.cc
index 0646736..35c9573 100644
--- a/chrome/browser/ui/autofill/chrome_autofill_client.cc
+++ b/chrome/browser/ui/autofill/chrome_autofill_client.cc
@@ -26,6 +26,7 @@
 #include "chrome/browser/ui/chrome_pages.h"
 #include "chrome/browser/ui/tabs/tab_strip_model_observer.h"
 #include "chrome/browser/web_data_service_factory.h"
+#include "chrome/common/features.h"
 #include "chrome/common/url_constants.h"
 #include "components/autofill/content/browser/content_autofill_driver.h"
 #include "components/autofill/content/common/autofill_messages.h"
@@ -39,7 +40,7 @@
 #include "content/public/browser/render_frame_host.h"
 #include "ui/gfx/geometry/rect.h"
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
 #include "chrome/browser/android/chrome_application.h"
 #include "chrome/browser/ui/android/autofill/autofill_logger_android.h"
 #else
@@ -60,7 +61,7 @@
       last_rfh_to_rac_(nullptr) {
   DCHECK(web_contents);
 
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(ANDROID_JAVA_UI)
   // Since ZoomController is also a WebContentsObserver, we need to be careful
   // about disconnecting from it since the relative order of destruction of
   // WebContentsObservers is not guaranteed. ZoomController silently clears
@@ -112,7 +113,7 @@
         Profile::FromBrowserContext(web_contents()->GetBrowserContext())
             ->GetOriginalProfile();
     base::Closure login_callback;
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(ANDROID_JAVA_UI)
     login_callback =
         LoginUIServiceFactory::GetShowLoginPopupCallbackForProfile(profile);
 #endif
@@ -130,13 +131,13 @@
 }
 
 void ChromeAutofillClient::ShowAutofillSettings() {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
   chrome::android::ChromeApplication::ShowAutofillSettings();
 #else
   Browser* browser = chrome::FindBrowserWithWebContents(web_contents());
   if (browser)
     chrome::ShowSettingsSubPage(browser, chrome::kAutofillSubPage);
-#endif  // #if defined(OS_ANDROID)
+#endif  // #if BUILDFLAG(ANDROID_JAVA_UI)
 }
 
 void ChromeAutofillClient::ShowUnmaskPrompt(
@@ -279,7 +280,7 @@
 }
 
 void ChromeAutofillClient::MainFrameWasResized(bool width_changed) {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
   // Ignore virtual keyboard showing and hiding a strip of suggestions.
   if (!width_changed)
     return;
@@ -312,10 +313,10 @@
 void ChromeAutofillClient::DidFillOrPreviewField(
     const base::string16& autofilled_value,
     const base::string16& profile_full_name) {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
   AutofillLoggerAndroid::DidFillOrPreviewField(autofilled_value,
                                                profile_full_name);
-#endif  // defined(OS_ANDROID)
+#endif  // BUILDFLAG(ANDROID_JAVA_UI)
 }
 
 void ChromeAutofillClient::OnFirstUserGestureObserved() {
diff --git a/chrome/browser/ui/autofill/credit_card_scanner_view.cc b/chrome/browser/ui/autofill/credit_card_scanner_view.cc
index 0f6e5b6..0d1bb08a 100644
--- a/chrome/browser/ui/autofill/credit_card_scanner_view.cc
+++ b/chrome/browser/ui/autofill/credit_card_scanner_view.cc
@@ -3,11 +3,12 @@
 // found in the LICENSE file.
 
 #include "chrome/browser/ui/autofill/credit_card_scanner_view.h"
+#include "chrome/common/features.h"
 
 namespace autofill {
 
 // Not implemented on other platforms yet.
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(ANDROID_JAVA_UI)
 // static
 bool CreditCardScannerView::CanShow() {
   return false;
diff --git a/chrome/browser/ui/autofill/password_generation_popup_controller_impl.cc b/chrome/browser/ui/autofill/password_generation_popup_controller_impl.cc
index bdc57b8..bc8b0ea 100644
--- a/chrome/browser/ui/autofill/password_generation_popup_controller_impl.cc
+++ b/chrome/browser/ui/autofill/password_generation_popup_controller_impl.cc
@@ -18,6 +18,7 @@
 #include "chrome/browser/ui/autofill/popup_constants.h"
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/chrome_pages.h"
+#include "chrome/common/features.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/grit/chromium_strings.h"
 #include "chrome/grit/generated_resources.h"
@@ -34,7 +35,7 @@
 #include "ui/gfx/geometry/rect_conversions.h"
 #include "ui/gfx/text_utils.h"
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
 #include "chrome/browser/android/chrome_application.h"
 #endif
 
@@ -232,7 +233,7 @@
 }
 
 void PasswordGenerationPopupControllerImpl::OnSavedPasswordsLinkClicked() {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
   chrome::android::ChromeApplication::ShowPasswordSettings();
 #else
   chrome::ShowSettingsSubPage(
diff --git a/chrome/browser/ui/blocked_content/popup_blocker_tab_helper.cc b/chrome/browser/ui/blocked_content/popup_blocker_tab_helper.cc
index ac28874..95f2a61 100644
--- a/chrome/browser/ui/blocked_content/popup_blocker_tab_helper.cc
+++ b/chrome/browser/ui/blocked_content/popup_blocker_tab_helper.cc
@@ -12,6 +12,7 @@
 #include "chrome/browser/ui/browser_navigator.h"
 #include "chrome/browser/ui/browser_navigator_params.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/common/features.h"
 #include "chrome/common/render_messages.h"
 #include "components/content_settings/core/browser/host_content_settings_map.h"
 #include "content/public/browser/navigation_controller.h"
@@ -22,7 +23,7 @@
 #include "content/public/browser/web_contents_delegate.h"
 #include "third_party/WebKit/public/web/WebWindowFeatures.h"
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
 #include "chrome/browser/ui/android/tab_model/tab_model_list.h"
 #endif
 
@@ -120,7 +121,7 @@
     return;
   // We set user_gesture to true here, so the new popup gets correctly focused.
   popup->params.user_gesture = true;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
   TabModelList::HandlePopupNavigation(&popup->params);
 #else
   chrome::Navigate(&popup->params);
diff --git a/chrome/browser/ui/browser_browsertest.cc b/chrome/browser/ui/browser_browsertest.cc
index 5857df7..5226b856 100644
--- a/chrome/browser/ui/browser_browsertest.cc
+++ b/chrome/browser/ui/browser_browsertest.cc
@@ -3126,9 +3126,7 @@
 
 class BrowserTestNonsecureURLRequest : public BrowserTest {
  public:
-  // TODO(thakis): Add back the `: BrowserTest()` once
-  // http://llvm.org/PR25370 is fixed, http://crbug.com/549765
-  BrowserTestNonsecureURLRequest() /* : BrowserTest() */ {}
+  BrowserTestNonsecureURLRequest() : BrowserTest() {}
   void SetUpOnMainThread() override {
     base::FilePath root_http;
     PathService::Get(chrome::DIR_TEST_DATA, &root_http);
diff --git a/chrome/browser/ui/browser_command_controller.cc b/chrome/browser/ui/browser_command_controller.cc
index b6f7942..ac6ec7d 100644
--- a/chrome/browser/ui/browser_command_controller.cc
+++ b/chrome/browser/ui/browser_command_controller.cc
@@ -7,6 +7,7 @@
 #include <string>
 
 #include "base/command_line.h"
+#include "base/debug/debugging_flags.h"
 #include "base/prefs/pref_service.h"
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/browser_process.h"
@@ -1279,7 +1280,7 @@
   command_updater_.UpdateCommandEnabled(IDC_VIEW_PASSWORDS, show_main_ui);
   command_updater_.UpdateCommandEnabled(IDC_ABOUT, show_main_ui);
   command_updater_.UpdateCommandEnabled(IDC_SHOW_APP_MENU, show_main_ui);
-#if defined (ENABLE_PROFILING) && !defined(NO_TCMALLOC)
+#if BUILDFLAG(ENABLE_PROFILING) && !defined(NO_TCMALLOC)
   command_updater_.UpdateCommandEnabled(IDC_PROFILING_ENABLED, show_main_ui);
 #endif
 
diff --git a/chrome/browser/ui/cocoa/location_bar/page_action_decoration.mm b/chrome/browser/ui/cocoa/location_bar/page_action_decoration.mm
index a911f4a..8a045c9 100644
--- a/chrome/browser/ui/cocoa/location_bar/page_action_decoration.mm
+++ b/chrome/browser/ui/cocoa/location_bar/page_action_decoration.mm
@@ -50,10 +50,9 @@
 
 PageActionDecoration::~PageActionDecoration() {}
 
-// Always |kPageActionIconMaxSize| wide.  |ImageDecoration| draws the
-// image centered.
+// Always |ActionIconSize| wide. |ImageDecoration| draws the image centered.
 CGFloat PageActionDecoration::GetWidthForSpace(CGFloat width) {
-  return ExtensionAction::kPageActionIconMaxSize;
+  return ExtensionAction::ActionIconSize();
 }
 
 bool PageActionDecoration::AcceptsMousePress() {
@@ -93,8 +92,8 @@
     SetToolTip(viewController_->GetTooltip(contents));
 
     // Set the image.
-    gfx::Size size(ExtensionAction::kPageActionIconMaxSize,
-                   ExtensionAction::kPageActionIconMaxSize);
+    gfx::Size size(ExtensionAction::ActionIconSize(),
+                   ExtensionAction::ActionIconSize());
     gfx::Image icon = viewController_->GetIcon(contents, size);
     if (!icon.IsEmpty()) {
       SetImage(icon.ToNSImage());
@@ -120,7 +119,7 @@
   // easier (the middle of the centered image is the middle of the
   // frame).
   const CGFloat delta_height =
-      NSHeight(frame) - ExtensionAction::kPageActionIconMaxSize;
+      NSHeight(frame) - ExtensionAction::ActionIconSize();
   const CGFloat bottom_inset = std::ceil(delta_height / 2.0);
 
   // Return a point just below the bottom of the maximal drawing area.
diff --git a/chrome/browser/ui/exclusive_access/exclusive_access_bubble.cc b/chrome/browser/ui/exclusive_access/exclusive_access_bubble.cc
index abf28c2..fe4de872 100644
--- a/chrome/browser/ui/exclusive_access/exclusive_access_bubble.cc
+++ b/chrome/browser/ui/exclusive_access/exclusive_access_bubble.cc
@@ -31,6 +31,7 @@
 const int ExclusiveAccessBubble::kSlideInDurationMs = 350;
 const int ExclusiveAccessBubble::kSlideOutDurationMs = 700;
 const int ExclusiveAccessBubble::kPopupTopPx = 45;
+const int ExclusiveAccessBubble::kSimplifiedPopupTopPx = 16;
 
 ExclusiveAccessBubble::ExclusiveAccessBubble(
     ExclusiveAccessManager* manager,
@@ -43,6 +44,27 @@
 ExclusiveAccessBubble::~ExclusiveAccessBubble() {
 }
 
+void ExclusiveAccessBubble::OnUserInput() {
+  if (!ExclusiveAccessManager::IsSimplifiedFullscreenUIEnabled())
+    return;
+
+  // We got some user input; reset the idle timer.
+  idle_timeout_.Stop();  // If the timer isn't running, this is a no-op.
+  idle_timeout_.Start(FROM_HERE,
+                      base::TimeDelta::FromMilliseconds(kIdleTimeMs), this,
+                      &ExclusiveAccessBubble::CheckMousePosition);
+
+  // If the notification suppression timer has elapsed, re-show it.
+  if (!suppress_notify_timeout_.IsRunning()) {
+    ShowAndStartTimers();
+    return;
+  }
+
+  // The timer has not elapsed, but the user provided some input. Reset the
+  // timer. (We only want to re-show the message after a period of inactivity.)
+  suppress_notify_timeout_.Reset();
+}
+
 void ExclusiveAccessBubble::StartWatchingMouse() {
   // Start the initial delay timer and begin watching the mouse.
   if (ExclusiveAccessManager::IsSimplifiedFullscreenUIEnabled()) {
@@ -97,25 +119,16 @@
 
   // Check to see whether the mouse is idle.
   if (cursor_pos != last_mouse_pos_) {
-    // The mouse moved; reset the idle timer.
-    idle_timeout_.Stop();  // If the timer isn't running, this is a no-op.
-    idle_timeout_.Start(FROM_HERE,
-                        base::TimeDelta::FromMilliseconds(kIdleTimeMs), this,
-                        &ExclusiveAccessBubble::CheckMousePosition);
-
-    if (ExclusiveAccessManager::IsSimplifiedFullscreenUIEnabled()) {
-      // If the notification suppression timer has elapsed, show the
-      // notification regardless of where the mouse is on the screen.
-      if (!suppress_notify_timeout_.IsRunning()) {
-        ShowAndStartTimers();
-        return;
-      } else {
-        // The timer has not elapsed, but the user moved the mouse. Reset the
-        // timer. (We only want to re-show the message after a period of
-        // inactivity.)
-        suppress_notify_timeout_.Reset();
-      }
+    if (!ExclusiveAccessManager::IsSimplifiedFullscreenUIEnabled()) {
+      // OnUserInput() will reset the idle timer in simplified mode. In classic
+      // mode, we need to do this here.
+      idle_timeout_.Stop();  // If the timer isn't running, this is a no-op.
+      idle_timeout_.Start(FROM_HERE,
+                          base::TimeDelta::FromMilliseconds(kIdleTimeMs), this,
+                          &ExclusiveAccessBubble::CheckMousePosition);
     }
+
+    OnUserInput();
   }
   last_mouse_pos_ = cursor_pos;
 
diff --git a/chrome/browser/ui/exclusive_access/exclusive_access_bubble.h b/chrome/browser/ui/exclusive_access/exclusive_access_bubble.h
index de663813..049df29 100644
--- a/chrome/browser/ui/exclusive_access/exclusive_access_bubble.h
+++ b/chrome/browser/ui/exclusive_access/exclusive_access_bubble.h
@@ -34,6 +34,10 @@
                                  ExclusiveAccessBubbleType bubble_type);
   ~ExclusiveAccessBubble() override;
 
+  // Informs the ExclusiveAccessBubble of some user input, which may update
+  // internal timers and/or re-display the bubble.
+  void OnUserInput();
+
  protected:
   static const int kPaddingPx;        // Amount of padding around the link
   static const int kInitialDelayMs;   // Initial time bubble remains onscreen
@@ -46,6 +50,8 @@
   static const int kSlideOutDurationMs;  // Duration of slide-out animation
   // Space between the popup and the top of the screen (excluding shadow).
   static const int kPopupTopPx;
+  // Space between top of screen and popup, in simplified UI.
+  static const int kSimplifiedPopupTopPx;
 
   // Returns the current desirable rect for the popup window.  If
   // |ignore_animation_state| is true this returns the rect assuming the popup
@@ -113,7 +119,7 @@
   // the user moving the mouse to the top of the screen and holding it there).
   base::OneShotTimer hide_timeout_;
 
-  // Timer to see how long the mouse has been idle.
+  // Timer to see how long the user has been idle (from all input sources).
   base::OneShotTimer idle_timeout_;
 
   // When this timer has elapsed, on the next mouse input, we will notify the
diff --git a/chrome/browser/ui/extensions/extension_action_view_controller.cc b/chrome/browser/ui/extensions/extension_action_view_controller.cc
index 20937975..fbb8ebb 100644
--- a/chrome/browser/ui/extensions/extension_action_view_controller.cc
+++ b/chrome/browser/ui/extensions/extension_action_view_controller.cc
@@ -27,7 +27,6 @@
 #include "extensions/common/extension.h"
 #include "extensions/common/feature_switch.h"
 #include "extensions/common/manifest_constants.h"
-#include "ui/base/resource/material_design/material_design_controller.h"
 #include "ui/gfx/image/image_skia.h"
 #include "ui/gfx/image/image_skia_operations.h"
 
@@ -366,16 +365,7 @@
   scoped_ptr<IconWithBadgeImageSource> image_source(
       new IconWithBadgeImageSource(size));
 
-  gfx::Image icon(icon_factory_.GetIcon(tab_id));
-  if (ui::MaterialDesignController::IsModeMaterial()) {
-    // TODO(tdanderson): Use a 16x16 icon if it exists instead of resizing.
-    icon = gfx::Image(gfx::ImageSkiaOperations::CreateResizedImage(
-        *icon.ToImageSkia(),
-        skia::ImageOperations::RESIZE_BEST,
-        gfx::Size(extension_misc::EXTENSION_ICON_BITTY,
-                  extension_misc::EXTENSION_ICON_BITTY)));
-  }
-  image_source->SetIcon(icon);
+  image_source->SetIcon(icon_factory_.GetIcon(tab_id));
 
   scoped_ptr<IconWithBadgeImageSource::Badge> badge;
   std::string badge_text = extension_action_->GetBadgeText(tab_id);
diff --git a/chrome/browser/ui/login/login_prompt_browsertest.cc b/chrome/browser/ui/login/login_prompt_browsertest.cc
index c4a7738c..e768b42e 100644
--- a/chrome/browser/ui/login/login_prompt_browsertest.cc
+++ b/chrome/browser/ui/login/login_prompt_browsertest.cc
@@ -1433,10 +1433,10 @@
   https_server.SetSSLConfig(net::EmbeddedTestServer::CERT_EXPIRED);
   ASSERT_TRUE(https_server.Start());
 
-  const char* kTestPage = "files/login/load_iframe_from_b.html";
+  const char* kTestPage = "/login/load_iframe_from_b.html";
 
   host_resolver()->AddRule("www.b.com", "127.0.0.1");
-  ASSERT_TRUE(test_server()->Start());
+  ASSERT_TRUE(embedded_test_server()->Start());
 
   content::WebContents* contents =
       browser()->tab_strip_model()->GetActiveWebContents();
@@ -1446,7 +1446,7 @@
 
   // Load a page that has a cross-domain iframe authentication. This should
   // trigger a login prompt but no login interstitial.
-  GURL test_page = test_server()->GetURL(kTestPage);
+  GURL test_page = embedded_test_server()->GetURL(kTestPage);
   GURL broken_ssl_page = https_server.GetURL("/");
   ASSERT_EQ("127.0.0.1", test_page.host());
   WindowedAuthNeededObserver auth_needed_waiter(controller);
diff --git a/chrome/browser/ui/passwords/manage_passwords_ui_controller.cc b/chrome/browser/ui/passwords/manage_passwords_ui_controller.cc
index 8548f343..83ce991 100644
--- a/chrome/browser/ui/passwords/manage_passwords_ui_controller.cc
+++ b/chrome/browser/ui/passwords/manage_passwords_ui_controller.cc
@@ -27,7 +27,7 @@
 #include "content/public/browser/navigation_details.h"
 #include "ui/base/l10n/l10n_util.h"
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
 #include "chrome/browser/android/chrome_application.h"
 #else
 #include "chrome/browser/ui/passwords/manage_passwords_icon_view.h"
@@ -149,7 +149,7 @@
     UpdateBubbleAndIconVisibility();
 }
 
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(ANDROID_JAVA_UI)
 void ManagePasswordsUIController::UpdateIconAndBubbleState(
     ManagePasswordsIconView* icon) {
   if (should_pop_up_bubble_) {
@@ -271,7 +271,7 @@
 }
 
 void ManagePasswordsUIController::NavigateToExternalPasswordManager() {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
   NOTREACHED();
 #else
   chrome::NavigateParams params(
@@ -284,7 +284,7 @@
 }
 
 void ManagePasswordsUIController::NavigateToSmartLockHelpPage() {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
   NOTREACHED();
 #else
   chrome::NavigateParams params(
@@ -296,7 +296,7 @@
 }
 
 void ManagePasswordsUIController::NavigateToPasswordManagerSettingsPage() {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
   chrome::android::ChromeApplication::ShowPasswordSettings();
 #else
   chrome::ShowSettingsSubPage(
@@ -340,7 +340,7 @@
     passwords_data_.OnInactive();
   }
 
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(ANDROID_JAVA_UI)
   Browser* browser = chrome::FindBrowserWithWebContents(web_contents());
   if (!browser)
     return;
@@ -375,14 +375,14 @@
 }
 
 void ManagePasswordsUIController::WasHidden() {
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(ANDROID_JAVA_UI)
   TabDialogs::FromWebContents(web_contents())->HideManagePasswordsBubble();
 #endif
 }
 
 void ManagePasswordsUIController::ShowBubbleWithoutUserInteraction() {
   DCHECK(should_pop_up_bubble_);
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(ANDROID_JAVA_UI)
   Browser* browser = chrome::FindBrowserWithWebContents(web_contents());
   if (!browser || browser->toolbar_model()->input_in_progress())
     return;
diff --git a/chrome/browser/ui/passwords/manage_passwords_ui_controller.h b/chrome/browser/ui/passwords/manage_passwords_ui_controller.h
index 19bebd25..dd745998 100644
--- a/chrome/browser/ui/passwords/manage_passwords_ui_controller.h
+++ b/chrome/browser/ui/passwords/manage_passwords_ui_controller.h
@@ -9,6 +9,7 @@
 #include "chrome/browser/ui/passwords/manage_passwords_state.h"
 #include "chrome/browser/ui/passwords/passwords_client_ui_delegate.h"
 #include "chrome/browser/ui/passwords/passwords_model_delegate.h"
+#include "chrome/common/features.h"
 #include "components/password_manager/core/browser/password_store.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "content/public/browser/web_contents_user_data.h"
@@ -57,7 +58,7 @@
   void OnLoginsChanged(
       const password_manager::PasswordStoreChangeList& changes) override;
 
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(ANDROID_JAVA_UI)
   // Set the state of the Omnibox icon, and possibly show the associated bubble
   // without user interaction.
   virtual void UpdateIconAndBubbleState(ManagePasswordsIconView* icon);
diff --git a/chrome/browser/ui/startup/startup_browser_creator.cc b/chrome/browser/ui/startup/startup_browser_creator.cc
index 9e9daf6..51b9dd33 100644
--- a/chrome/browser/ui/startup/startup_browser_creator.cc
+++ b/chrome/browser/ui/startup/startup_browser_creator.cc
@@ -92,8 +92,7 @@
 
 #if defined(OS_WIN)
 #include "chrome/browser/metrics/jumplist_metrics_win.h"
-#include "components/search_engines/detect_desktop_search_win.h"
-#include "components/search_engines/search_engines_switches.h"
+#include "components/search_engines/desktop_search_win.h"
 #endif
 
 #if defined(ENABLE_PRINT_PREVIEW)
@@ -553,16 +552,16 @@
     GURL url = GURL(param.MaybeAsASCII());
 
 #if defined(OS_WIN)
-    if (command_line.HasSwitch(
-            switches::kUseDefaultSearchProviderForDesktopSearch)) {
+    if (ShouldRedirectWindowsDesktopSearchToDefaultSearchEngine(
+            profile->GetPrefs())) {
       TemplateURLService* template_url_service =
           TemplateURLServiceFactory::GetForProfile(profile);
       DCHECK(template_url_service);
       base::string16 search_terms;
       if (DetectWindowsDesktopSearch(
               url, template_url_service->search_terms_data(), &search_terms)) {
-        GURL search_url(GetDefaultSearchURLForSearchTerms(template_url_service,
-                                                          search_terms));
+        const GURL search_url(GetDefaultSearchURLForSearchTerms(
+            template_url_service, search_terms));
         if (search_url.is_valid()) {
           urls.push_back(search_url);
           continue;
diff --git a/chrome/browser/ui/startup/startup_browser_creator.h b/chrome/browser/ui/startup/startup_browser_creator.h
index 6ee80670..663285a 100644
--- a/chrome/browser/ui/startup/startup_browser_creator.h
+++ b/chrome/browser/ui/startup/startup_browser_creator.h
@@ -132,6 +132,8 @@
                            ReadingWasRestartedAfterRestart);
   FRIEND_TEST_ALL_PREFIXES(StartupBrowserCreatorTest, UpdateWithTwoProfiles);
   FRIEND_TEST_ALL_PREFIXES(StartupBrowserCreatorTest, LastUsedProfileActivated);
+  FRIEND_TEST_ALL_PREFIXES(StartupBrowserCreatorWinTest,
+                           GetURLsFromCommandLineWithDesktopSearchURL);
 
   // Returns the list of URLs to open from the command line. The returned
   // vector is empty if the user didn't specify any URLs on the command line.
diff --git a/chrome/browser/ui/startup/startup_browser_creator_triggered_reset_browsertest_win.cc b/chrome/browser/ui/startup/startup_browser_creator_triggered_reset_browsertest_win.cc
index c9b8c2b..6ebb1b9b 100644
--- a/chrome/browser/ui/startup/startup_browser_creator_triggered_reset_browsertest_win.cc
+++ b/chrome/browser/ui/startup/startup_browser_creator_triggered_reset_browsertest_win.cc
@@ -220,10 +220,10 @@
   profile_manager->RegisterTestingProfile(other_profile, true, false);
 
   // Use a couple same-site HTTP URLs.
-  ASSERT_TRUE(test_server()->Start());
+  ASSERT_TRUE(embedded_test_server()->Start());
   std::vector<GURL> urls;
-  urls.push_back(test_server()->GetURL("files/title1.html"));
-  urls.push_back(test_server()->GetURL("files/title2.html"));
+  urls.push_back(embedded_test_server()->GetURL("/title1.html"));
+  urls.push_back(embedded_test_server()->GetURL("/title2.html"));
 
   // Set the startup preference to open these URLs.
   SessionStartupPref other_prefs(SessionStartupPref::URLS);
diff --git a/chrome/browser/ui/startup/startup_browser_creator_win_unittest.cc b/chrome/browser/ui/startup/startup_browser_creator_win_unittest.cc
new file mode 100644
index 0000000..1821487
--- /dev/null
+++ b/chrome/browser/ui/startup/startup_browser_creator_win_unittest.cc
@@ -0,0 +1,90 @@
+// 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.
+
+#include "chrome/browser/ui/startup/startup_browser_creator.h"
+
+#include <vector>
+
+#include "base/command_line.h"
+#include "base/feature_list.h"
+#include "base/macros.h"
+#include "base/prefs/pref_service.h"
+#include "chrome/browser/search_engines/template_url_service_factory.h"
+#include "chrome/browser/search_engines/template_url_service_factory_test_util.h"
+#include "chrome/test/base/testing_profile.h"
+#include "components/search_engines/desktop_search_win.h"
+#include "components/search_engines/util.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+class StartupBrowserCreatorWinTest : public testing::Test {
+ public:
+  StartupBrowserCreatorWinTest() {}
+
+ protected:
+  void SetWindowsDesktopSearchFeatureEnabled(bool enabled) {
+    base::FeatureList::ClearInstanceForTesting();
+    scoped_ptr<base::FeatureList> feature_list(new base::FeatureList);
+    if (enabled) {
+      feature_list->InitializeFromCommandLine(
+          kWindowsDesktopSearchRedirectionFeature.name, std::string());
+    }
+    base::FeatureList::SetInstance(std::move(feature_list));
+  }
+
+ private:
+  content::TestBrowserThreadBundle thread_bundle_;
+
+  DISALLOW_COPY_AND_ASSIGN(StartupBrowserCreatorWinTest);
+};
+
+TEST_F(StartupBrowserCreatorWinTest,
+       GetURLsFromCommandLineWithDesktopSearchURL) {
+  const char kDesktopSearchURL[] =
+      "https://www.bing.com/search?q=keyword&form=WNSGPH";
+
+  TestingProfile profile;
+  TemplateURLServiceFactoryTestUtil template_url_service_factory_test_util(
+      &profile);
+
+  base::CommandLine command_line(base::CommandLine::NO_PROGRAM);
+  command_line.AppendArg(kDesktopSearchURL);
+
+  // Expected vectors of URLs.
+  const std::vector<GURL> desktop_search_url_vector({GURL(kDesktopSearchURL)});
+  const std::vector<GURL> default_search_url_vector(
+      {GetDefaultSearchURLForSearchTerms(
+          TemplateURLServiceFactory::GetForProfile(&profile), L"keyword")});
+
+  // Preference unset, feature enabled.
+  SetWindowsDesktopSearchFeatureEnabled(true);
+  EXPECT_EQ(desktop_search_url_vector,
+            StartupBrowserCreator::GetURLsFromCommandLine(
+                command_line, base::FilePath(), &profile));
+
+  // Preference set to disabled, feature enabled.
+  profile.GetPrefs()->SetBoolean(prefs::kWindowsDesktopSearchRedirectionPref,
+                                 false);
+  SetWindowsDesktopSearchFeatureEnabled(true);
+  EXPECT_EQ(desktop_search_url_vector,
+            StartupBrowserCreator::GetURLsFromCommandLine(
+                command_line, base::FilePath(), &profile));
+
+  // Preference set to enabled, feature enabled.
+  profile.GetPrefs()->SetBoolean(prefs::kWindowsDesktopSearchRedirectionPref,
+                                 true);
+  SetWindowsDesktopSearchFeatureEnabled(true);
+  EXPECT_EQ(default_search_url_vector,
+            StartupBrowserCreator::GetURLsFromCommandLine(
+                command_line, base::FilePath(), &profile));
+
+  // Preference set to enabled, feature disabled.
+  profile.GetPrefs()->SetBoolean(prefs::kWindowsDesktopSearchRedirectionPref,
+                                 true);
+  SetWindowsDesktopSearchFeatureEnabled(false);
+  EXPECT_EQ(desktop_search_url_vector,
+            StartupBrowserCreator::GetURLsFromCommandLine(
+                command_line, base::FilePath(), &profile));
+}
diff --git a/chrome/browser/ui/tab_helpers.cc b/chrome/browser/ui/tab_helpers.cc
index b9947de..5bfbf050 100644
--- a/chrome/browser/ui/tab_helpers.cc
+++ b/chrome/browser/ui/tab_helpers.cc
@@ -39,6 +39,7 @@
 #include "chrome/browser/ui/tab_contents/core_tab_helper.h"
 #include "chrome/browser/ui/tab_dialogs.h"
 #include "chrome/common/chrome_switches.h"
+#include "chrome/common/features.h"
 #include "components/autofill/content/browser/content_autofill_driver_factory.h"
 #include "components/autofill/core/browser/autofill_manager.h"
 #include "components/dom_distiller/content/browser/web_contents_main_frame_observer.h"
@@ -49,7 +50,7 @@
 #include "components/tracing/tracing_switches.h"
 #include "content/public/browser/web_contents.h"
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
 #include "chrome/browser/android/data_usage/data_use_tab_helper.h"
 #include "chrome/browser/android/voice_search_tab_helper.h"
 #include "chrome/browser/android/webapps/single_tab_mode_tab_helper.h"
@@ -69,7 +70,7 @@
 #include "components/pdf/browser/pdf_web_contents_helper.h"
 #include "components/ui/zoom/zoom_controller.h"
 #include "components/web_modal/web_contents_modal_dialog_manager.h"
-#endif  // defined(OS_ANDROID)
+#endif  // BUILDFLAG(ANDROID_JAVA_UI)
 
 #if defined(OS_WIN)
 #include "chrome/browser/ui/metro_pin_tab_helper_win.h"
@@ -131,7 +132,7 @@
   // SessionTabHelper comes first because it sets up the tab ID, and other
   // helpers may rely on that.
   SessionTabHelper::CreateForWebContents(web_contents);
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(ANDROID_JAVA_UI)
   // ZoomController comes before common tab helpers since ChromeAutofillClient
   // may want to register as a ZoomObserver with it.
   ui_zoom::ZoomController::CreateForWebContents(web_contents);
@@ -179,7 +180,7 @@
 
   // --- Platform-specific tab helpers ---
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
   ContextMenuHelper::CreateForWebContents(web_contents);
   DataUseTabHelper::CreateForWebContents(web_contents);
   SingleTabModeTabHelper::CreateForWebContents(web_contents);
@@ -228,14 +229,14 @@
   SupervisedUserNavigationObserver::CreateForWebContents(web_contents);
 #endif
 
-#if defined(ENABLE_PRINTING) && !defined(OS_ANDROID)
+#if defined(ENABLE_PRINTING) && !BUILDFLAG(ANDROID_JAVA_UI)
 #if defined(ENABLE_PRINT_PREVIEW)
   printing::PrintViewManager::CreateForWebContents(web_contents);
   printing::PrintPreviewMessageHandler::CreateForWebContents(web_contents);
 #else
   printing::PrintViewManagerBasic::CreateForWebContents(web_contents);
 #endif  // defined(ENABLE_PRINT_PREVIEW)
-#endif  // defined(ENABLE_PRINTING) && !defined(OS_ANDROID)
+#endif  // defined(ENABLE_PRINTING) && !BUILDFLAG(ANDROID_JAVA_UI)
 
   bool enabled_distiller = base::CommandLine::ForCurrentProcess()->HasSwitch(
       switches::kEnableDomDistiller);
diff --git a/chrome/browser/ui/toolbar/app_menu_model.cc b/chrome/browser/ui/toolbar/app_menu_model.cc
index 93f8704f2..f25c0fd7 100644
--- a/chrome/browser/ui/toolbar/app_menu_model.cc
+++ b/chrome/browser/ui/toolbar/app_menu_model.cc
@@ -8,6 +8,7 @@
 #include <cmath>
 
 #include "base/command_line.h"
+#include "base/debug/debugging_flags.h"
 #include "base/metrics/histogram.h"
 #include "base/prefs/pref_service.h"
 #include "base/strings/string_number_conversions.h"
@@ -322,7 +323,7 @@
   AddSeparator(ui::NORMAL_SEPARATOR);
   AddItemWithStringId(IDC_DEV_TOOLS, IDS_DEV_TOOLS);
 
-#if defined(ENABLE_PROFILING) && !defined(NO_TCMALLOC)
+#if BUILDFLAG(ENABLE_PROFILING) && !defined(NO_TCMALLOC)
   AddSeparator(ui::NORMAL_SEPARATOR);
   AddCheckItemWithStringId(IDC_PROFILING_ENABLED, IDS_PROFILING_ENABLED);
 #endif
diff --git a/chrome/browser/ui/toolbar/component_toolbar_actions_browsertest.cc b/chrome/browser/ui/toolbar/component_toolbar_actions_browsertest.cc
index b5550c84..ddf66be 100644
--- a/chrome/browser/ui/toolbar/component_toolbar_actions_browsertest.cc
+++ b/chrome/browser/ui/toolbar/component_toolbar_actions_browsertest.cc
@@ -54,7 +54,7 @@
 
   // There should only have been one created component action.
   EXPECT_EQ(1u, ComponentToolbarActionsFactory::GetInstance()
-                    ->GetComponentIds(browser()->profile())
+                    ->GetInitialComponentIds(browser()->profile())
                     .size());
 
   const std::vector<ToolbarActionViewController*>& actions =
diff --git a/chrome/browser/ui/toolbar/component_toolbar_actions_factory.cc b/chrome/browser/ui/toolbar/component_toolbar_actions_factory.cc
index 0c45060..956c3cb7 100644
--- a/chrome/browser/ui/toolbar/component_toolbar_actions_factory.cc
+++ b/chrome/browser/ui/toolbar/component_toolbar_actions_factory.cc
@@ -37,7 +37,7 @@
   return testing_factory_ ? testing_factory_ : &lazy_factory.Get();
 }
 
-std::set<std::string> ComponentToolbarActionsFactory::GetComponentIds(
+std::set<std::string> ComponentToolbarActionsFactory::GetInitialComponentIds(
     Profile* profile) {
   std::set<std::string> component_ids;
 
@@ -59,7 +59,7 @@
   // This is currently behind the extension-action-redesign flag, as it is
   // designed for the new toolbar.
   DCHECK(extensions::FeatureSwitch::extension_action_redesign()->IsEnabled());
-  DCHECK(GetComponentIds(browser->profile()).count(id));
+  DCHECK(GetInitialComponentIds(browser->profile()).count(id));
 
   // Add component toolbar actions here.
   // This current design means that the ComponentToolbarActionsFactory is aware
diff --git a/chrome/browser/ui/toolbar/component_toolbar_actions_factory.h b/chrome/browser/ui/toolbar/component_toolbar_actions_factory.h
index ffdc126a4..f8fa607 100644
--- a/chrome/browser/ui/toolbar/component_toolbar_actions_factory.h
+++ b/chrome/browser/ui/toolbar/component_toolbar_actions_factory.h
@@ -29,7 +29,7 @@
   static ComponentToolbarActionsFactory* GetInstance();
 
   // Returns a vector of IDs of the component actions.
-  virtual std::set<std::string> GetComponentIds(Profile* profile);
+  virtual std::set<std::string> GetInitialComponentIds(Profile* profile);
 
   // Returns a collection of controllers for component actions. Declared
   // virtual for testing.
diff --git a/chrome/browser/ui/toolbar/mock_component_toolbar_actions_factory.cc b/chrome/browser/ui/toolbar/mock_component_toolbar_actions_factory.cc
index 05ecd87..01fdd05f 100644
--- a/chrome/browser/ui/toolbar/mock_component_toolbar_actions_factory.cc
+++ b/chrome/browser/ui/toolbar/mock_component_toolbar_actions_factory.cc
@@ -21,8 +21,8 @@
   ComponentToolbarActionsFactory::SetTestingFactory(nullptr);
 }
 
-std::set<std::string> MockComponentToolbarActionsFactory::GetComponentIds(
-    Profile* profile) {
+std::set<std::string>
+MockComponentToolbarActionsFactory::GetInitialComponentIds(Profile* profile) {
   std::set<std::string> ids;
   ids.insert(kActionIdForTesting);
   return ids;
diff --git a/chrome/browser/ui/toolbar/mock_component_toolbar_actions_factory.h b/chrome/browser/ui/toolbar/mock_component_toolbar_actions_factory.h
index 6770013..675cc28 100644
--- a/chrome/browser/ui/toolbar/mock_component_toolbar_actions_factory.h
+++ b/chrome/browser/ui/toolbar/mock_component_toolbar_actions_factory.h
@@ -20,7 +20,7 @@
   ~MockComponentToolbarActionsFactory() override;
 
   // ComponentToolbarActionsFactory:
-  std::set<std::string> GetComponentIds(Profile* profile) override;
+  std::set<std::string> GetInitialComponentIds(Profile* profile) override;
   scoped_ptr<ToolbarActionViewController> GetComponentToolbarActionForId(
       const std::string& id,
       Browser* browser) override;
diff --git a/chrome/browser/ui/toolbar/toolbar_action_view_controller.h b/chrome/browser/ui/toolbar/toolbar_action_view_controller.h
index 4702922..d9f3ae6 100644
--- a/chrome/browser/ui/toolbar/toolbar_action_view_controller.h
+++ b/chrome/browser/ui/toolbar/toolbar_action_view_controller.h
@@ -24,7 +24,7 @@
 
 // The basic controller class for an action that is shown on the toolbar -
 // an extension action (like browser actions) or a component action (like
-// chromecast).
+// Media Router).
 class ToolbarActionViewController {
  public:
   virtual ~ToolbarActionViewController() {}
diff --git a/chrome/browser/ui/toolbar/toolbar_actions_bar.cc b/chrome/browser/ui/toolbar/toolbar_actions_bar.cc
index e88db9dc..442119b 100644
--- a/chrome/browser/ui/toolbar/toolbar_actions_bar.cc
+++ b/chrome/browser/ui/toolbar/toolbar_actions_bar.cc
@@ -9,7 +9,6 @@
 #include "base/profiler/scoped_tracker.h"
 #include "base/single_thread_task_runner.h"
 #include "base/thread_task_runner_handle.h"
-#include "chrome/browser/extensions/extension_action_manager.h"
 #include "chrome/browser/extensions/extension_message_bubble_controller.h"
 #include "chrome/browser/extensions/extension_util.h"
 #include "chrome/browser/profiles/profile.h"
@@ -26,7 +25,6 @@
 #include "chrome/common/pref_names.h"
 #include "components/crx_file/id_util.h"
 #include "components/pref_registry/pref_registry_syncable.h"
-#include "extensions/browser/extension_registry.h"
 #include "extensions/browser/extension_system.h"
 #include "extensions/browser/runtime_data.h"
 #include "extensions/common/extension.h"
@@ -597,30 +595,15 @@
   }
 }
 
-void ToolbarActionsBar::OnToolbarActionAdded(const std::string& action_id,
-                                             int index) {
-  DCHECK(GetActionForId(action_id) == nullptr)
-      << "Asked to add a toolbar action view for an extension that already "
+void ToolbarActionsBar::OnToolbarActionAdded(
+    const ToolbarActionsModel::ToolbarItem& item,
+    int index) {
+  DCHECK(GetActionForId(item.id) == nullptr)
+      << "Asked to add a toolbar action view for an action that already "
          "exists";
 
-  // TODO(devlin): This is a minor layering violation and the model should pass
-  // in an action directly.
-  const extensions::Extension* extension =
-      extensions::ExtensionRegistry::Get(browser_->profile())
-          ->enabled_extensions()
-          .GetByID(action_id);
-  // Only extensions should be added after initialization.
-  DCHECK(extension);
-
-  toolbar_actions_.insert(
-      toolbar_actions_.begin() + index,
-      new ExtensionActionViewController(
-          extension,
-          browser_,
-          extensions::ExtensionActionManager::Get(browser_->profile())->
-              GetExtensionAction(*extension),
-          this));
-
+  toolbar_actions_.insert(toolbar_actions_.begin() + index,
+                          model_->CreateActionForItem(browser_, this, item));
   delegate_->AddViewForAction(toolbar_actions_[index], index);
 
   // If we are still initializing the container, don't bother animating.
@@ -628,7 +611,7 @@
     return;
 
   // We may need to resize (e.g. to show the new icon, or the chevron). We don't
-  // need to check if the extension is upgrading here, because ResizeDelegate()
+  // need to check if an extension is upgrading here, because ResizeDelegate()
   // checks to see if the container is already the proper size, and because
   // if the action is newly incognito enabled, even though it's a reload, it's
   // a new extension to this toolbar.
diff --git a/chrome/browser/ui/toolbar/toolbar_actions_bar.h b/chrome/browser/ui/toolbar/toolbar_actions_bar.h
index b8757d6..6d3bf93 100644
--- a/chrome/browser/ui/toolbar/toolbar_actions_bar.h
+++ b/chrome/browser/ui/toolbar/toolbar_actions_bar.h
@@ -244,7 +244,8 @@
   using ToolbarActions = ScopedVector<ToolbarActionViewController>;
 
   // ToolbarActionsModel::Observer:
-  void OnToolbarActionAdded(const std::string& action_id, int index) override;
+  void OnToolbarActionAdded(const ToolbarActionsModel::ToolbarItem& item,
+                            int index) override;
   void OnToolbarActionRemoved(const std::string& action_id) override;
   void OnToolbarActionMoved(const std::string& action_id, int index) override;
   void OnToolbarActionUpdated(const std::string& action_id) override;
diff --git a/chrome/browser/ui/toolbar/toolbar_actions_model.cc b/chrome/browser/ui/toolbar/toolbar_actions_model.cc
index 23f6dba..2d2d479 100644
--- a/chrome/browser/ui/toolbar/toolbar_actions_model.cc
+++ b/chrome/browser/ui/toolbar/toolbar_actions_model.cc
@@ -145,9 +145,8 @@
     content::WebContents* web_contents,
     content::BrowserContext* browser_context) {
   // Notify observers if the extension exists and is in the model.
-  if (std::find(toolbar_items_.begin(), toolbar_items_.end(),
-                ToolbarItem(extension_action->extension_id(),
-                            EXTENSION_ACTION)) != toolbar_items_.end()) {
+  if (HasItem(
+          ToolbarItem(extension_action->extension_id(), EXTENSION_ACTION))) {
     FOR_EACH_OBSERVER(Observer, observers_,
                       OnToolbarActionUpdated(extension_action->extension_id()));
   }
@@ -217,12 +216,8 @@
   // We don't want to add the same extension twice. It may have already been
   // added by EXTENSION_BROWSER_ACTION_VISIBILITY_CHANGED below, if the user
   // hides the browser action and then disables and enables the extension.
-  if (std::find(toolbar_items_.begin(), toolbar_items_.end(),
-                ToolbarItem(extension->id(), EXTENSION_ACTION)) !=
-      toolbar_items_.end())
-    return;
-
-  AddExtension(extension);
+  if (!HasItem(ToolbarItem(extension->id(), EXTENSION_ACTION)))
+    AddExtension(extension);
 }
 
 void ToolbarActionsModel::OnExtensionUnloaded(
@@ -238,9 +233,12 @@
     extensions::UninstallReason reason) {
   // Remove the extension id from the ordered list, if it exists (the extension
   // might not be represented in the list because it might not have an icon).
-  std::vector<std::string>::iterator pos =
-      std::find(last_known_positions_.begin(), last_known_positions_.end(),
-                extension->id());
+  RemovePref(ToolbarItem(extension->id(), EXTENSION_ACTION));
+}
+
+void ToolbarActionsModel::RemovePref(const ToolbarItem& item) {
+  std::vector<std::string>::iterator pos = std::find(
+      last_known_positions_.begin(), last_known_positions_.end(), item.id);
 
   if (pos != last_known_positions_.end()) {
     last_known_positions_.erase(pos);
@@ -309,23 +307,27 @@
 }
 
 void ToolbarActionsModel::AddExtension(const extensions::Extension* extension) {
-  // We only use AddExtension() once the system is initialized.
-  DCHECK(actions_initialized_);
   if (!ShouldAddExtension(extension))
     return;
 
+  AddItem(ToolbarItem(extension->id(), EXTENSION_ACTION),
+          extensions::Manifest::IsComponentLocation(extension->location()));
+}
+
+void ToolbarActionsModel::AddItem(const ToolbarItem& item, bool is_component) {
+  // We only use AddItem() once the system is initialized.
+  DCHECK(actions_initialized_);
+
   // See if we have a last known good position for this extension.
   bool is_new_extension =
       std::find(last_known_positions_.begin(), last_known_positions_.end(),
-                extension->id()) == last_known_positions_.end();
+                item.id) == last_known_positions_.end();
 
   // New extensions go at the right (end) of the visible extensions. Other
   // extensions go at their previous position.
   size_t new_index = 0;
   if (is_new_extension) {
-    new_index = extensions::Manifest::IsComponentLocation(extension->location())
-                    ? 0
-                    : visible_icon_count();
+    new_index = is_component ? 0 : visible_icon_count();
     // For the last-known position, we use the index of the extension that is
     // just before this extension, plus one. (Note that this isn't the same
     // as new_index + 1, because last_known_positions_ can include disabled
@@ -342,22 +344,20 @@
     new_last_known_index =
         std::min<int>(new_last_known_index, last_known_positions_.size());
     last_known_positions_.insert(
-        last_known_positions_.begin() + new_last_known_index, extension->id());
+        last_known_positions_.begin() + new_last_known_index, item.id);
     UpdatePrefs();
   } else {
-    new_index = FindNewPositionFromLastKnownGood(
-        ToolbarItem(extension->id(), EXTENSION_ACTION));
+    new_index = FindNewPositionFromLastKnownGood(item);
   }
 
-  toolbar_items_.insert(toolbar_items_.begin() + new_index,
-                        ToolbarItem(extension->id(), EXTENSION_ACTION));
+  toolbar_items_.insert(toolbar_items_.begin() + new_index, item);
 
   // If we're currently highlighting, then even though we add a browser action
   // to the full list (|toolbar_items_|, there won't be another *visible*
   // browser action, which was what the observers care about.
   if (!is_highlighting()) {
     FOR_EACH_OBSERVER(Observer, observers_,
-                      OnToolbarActionAdded(extension->id(), new_index));
+                      OnToolbarActionAdded(item, new_index));
 
     int visible_count_delta = 0;
     if (is_new_extension && !all_icons_visible()) {
@@ -372,8 +372,7 @@
       // Find what the index will be in the main bar. Because Observer calls are
       // nondeterministic, we can't just assume the main bar will have the
       // extension and look it up.
-      size_t main_index = main_model->FindNewPositionFromLastKnownGood(
-          ToolbarItem(extension->id(), EXTENSION_ACTION));
+      size_t main_index = main_model->FindNewPositionFromLastKnownGood(item);
       bool visible = main_index < main_model->visible_icon_count();
       // We may need to adjust the visible count if the incognito bar isn't
       // showing all icons and this one is visible, or if it is showing all
@@ -389,11 +388,9 @@
   }
 }
 
-void ToolbarActionsModel::RemoveExtension(
-    const extensions::Extension* extension) {
+void ToolbarActionsModel::RemoveItem(const ToolbarItem& item) {
   std::vector<ToolbarItem>::iterator pos =
-      std::find(toolbar_items_.begin(), toolbar_items_.end(),
-                ToolbarItem(extension->id(), EXTENSION_ACTION));
+      std::find(toolbar_items_.begin(), toolbar_items_.end(), item);
 
   if (pos == toolbar_items_.end())
     return;
@@ -404,27 +401,29 @@
 
   toolbar_items_.erase(pos);
 
-  // If we're in highlight mode, we also have to remove the extension from
+  // If we're in highlight mode, we also have to remove the action from
   // the highlighted list.
   if (is_highlighting()) {
-    pos = std::find(highlighted_items_.begin(), highlighted_items_.end(),
-                    ToolbarItem(extension->id(), EXTENSION_ACTION));
+    pos = std::find(highlighted_items_.begin(), highlighted_items_.end(), item);
     if (pos != highlighted_items_.end()) {
       highlighted_items_.erase(pos);
-      FOR_EACH_OBSERVER(Observer, observers_,
-                        OnToolbarActionRemoved(extension->id()));
+      FOR_EACH_OBSERVER(Observer, observers_, OnToolbarActionRemoved(item.id));
       // If the highlighted list is now empty, we stop highlighting.
       if (highlighted_items_.empty())
         StopHighlighting();
     }
   } else {
-    FOR_EACH_OBSERVER(Observer, observers_,
-                      OnToolbarActionRemoved(extension->id()));
+    FOR_EACH_OBSERVER(Observer, observers_, OnToolbarActionRemoved(item.id));
   }
 
   UpdatePrefs();
 }
 
+void ToolbarActionsModel::RemoveExtension(
+    const extensions::Extension* extension) {
+  RemoveItem(ToolbarItem(extension->id(), EXTENSION_ACTION));
+}
+
 // Combine the currently enabled extensions that have browser actions (which
 // we get from the ExtensionRegistry) and component actions (which we get from
 // ComponentToolbarActionsFactory) with the ordering we get from the pref
@@ -473,7 +472,8 @@
 
   // Next, add the component action ids.
   std::set<std::string> component_ids =
-      ComponentToolbarActionsFactory::GetInstance()->GetComponentIds(profile_);
+      ComponentToolbarActionsFactory::GetInstance()->GetInitialComponentIds(
+          profile_);
   for (const std::string& id : component_ids)
     all_actions.push_back(ToolbarItem(id, COMPONENT_ACTION));
 
@@ -563,6 +563,26 @@
   }
 }
 
+bool ToolbarActionsModel::HasItem(const ToolbarItem& item) const {
+  return std::find(toolbar_items_.begin(), toolbar_items_.end(), item) !=
+         toolbar_items_.end();
+}
+
+void ToolbarActionsModel::AddComponentAction(const std::string& action_id) {
+  DCHECK(use_redesign_);
+  ToolbarItem component_item(action_id, COMPONENT_ACTION);
+  DCHECK(!HasItem(component_item));
+  AddItem(component_item, true);
+}
+
+void ToolbarActionsModel::RemoveComponentAction(const std::string& action_id) {
+  DCHECK(use_redesign_);
+  ToolbarItem component_item(action_id, COMPONENT_ACTION);
+  DCHECK(HasItem(component_item));
+  RemoveItem(component_item);
+  RemovePref(component_item);
+}
+
 void ToolbarActionsModel::IncognitoPopulate() {
   DCHECK(profile_->IsOffTheRecord());
   const ToolbarActionsModel* original_model =
@@ -577,7 +597,8 @@
   visible_icon_count_ = 0;
 
   std::set<std::string> component_ids =
-      ComponentToolbarActionsFactory::GetInstance()->GetComponentIds(profile_);
+      ComponentToolbarActionsFactory::GetInstance()->GetInitialComponentIds(
+          profile_);
   for (std::vector<ToolbarItem>::const_iterator iter =
            original_model->toolbar_items_.begin();
        iter != original_model->toolbar_items_.end(); ++iter) {
@@ -621,9 +642,7 @@
                                               bool is_now_visible) {
   // Hiding works differently with the new and old toolbars.
   if (use_redesign_) {
-    DCHECK(std::find(toolbar_items_.begin(), toolbar_items_.end(),
-                     ToolbarItem(action_id, EXTENSION_ACTION)) !=
-           toolbar_items_.end());
+    DCHECK(HasItem(ToolbarItem(action_id, EXTENSION_ACTION)));
 
     int new_size = 0;
     int new_index = 0;
diff --git a/chrome/browser/ui/toolbar/toolbar_actions_model.h b/chrome/browser/ui/toolbar/toolbar_actions_model.h
index e94938d..cfde0a68 100644
--- a/chrome/browser/ui/toolbar/toolbar_actions_model.h
+++ b/chrome/browser/ui/toolbar/toolbar_actions_model.h
@@ -60,7 +60,7 @@
     ToolbarItem(const std::string& action_id, ActionType action_type)
         : id(action_id), type(action_type) {}
 
-    bool operator==(const ToolbarItem& other) { return other.id == id; }
+    bool operator==(const ToolbarItem& other) const { return other.id == id; }
 
     std::string id;
     ActionType type;
@@ -76,10 +76,9 @@
   // delegate.
   class Observer {
    public:
-    // Signals that an action with |id| has been added to the toolbar at
-    // |index|. This will *only* be called after the toolbar model has been
-    // initialized.
-    virtual void OnToolbarActionAdded(const std::string& id, int index) = 0;
+    // Signals that |item| has been added to the toolbar at |index|. This will
+    // *only* be called after the toolbar model has been initialized.
+    virtual void OnToolbarActionAdded(const ToolbarItem& item, int index) = 0;
 
     // Signals that the given action with |id| has been removed from the
     // toolbar.
@@ -183,6 +182,11 @@
   // showing new icons as a result.
   bool RedesignIsShowingNewIcons() const;
 
+  // Adds or removes the component action labeled by |action_id| from the
+  // toolbar model.  The caller must not add the same action twice.
+  void AddComponentAction(const std::string& action_id);
+  void RemoveComponentAction(const std::string& action_id);
+
  private:
   // Callback when actions are ready.
   void OnReady();
@@ -207,10 +211,11 @@
                                           bool is_now_visible) override;
 
   // To be called after the extension service is ready; gets loaded extensions
-  // from the ExtensionRegistry and their saved order from the pref service
-  // and constructs |toolbar_items_| from these data. IncognitoPopulate()
-  // takes the shortcut - looking at the regular model's content and modifying
-  // it.
+  // from the ExtensionRegistry, their saved order from the pref service, and
+  // the initial set of component actions from the
+  // ComponentToolbarActionsFactory, and constructs |toolbar_items_| from these
+  // data. IncognitoPopulate() takes the shortcut - looking at the regular
+  // model's content and modifying it.
   void InitializeActionList();
   void Populate();
   void IncognitoPopulate();
@@ -218,6 +223,9 @@
   // Save the model to prefs.
   void UpdatePrefs();
 
+  // Removes any preference for |item| and saves the model to prefs.
+  void RemovePref(const ToolbarItem& item);
+
   // Finds the last known visible position of the icon for |action|. The value
   // returned is a zero-based index into the vector of visible items.
   size_t FindNewPositionFromLastKnownGood(const ToolbarItem& action);
@@ -229,6 +237,21 @@
   void AddExtension(const extensions::Extension* extension);
   void RemoveExtension(const extensions::Extension* extension);
 
+  // Returns true if |item| is in the toolbar model.
+  bool HasItem(const ToolbarItem& item) const;
+
+  // Adds |item| to the toolbar.  If the item has an existing preference for
+  // toolbar position, that will be used to determine its location.  If
+  // |is_component| is true, the item will be given a default postion of 0,
+  // otherwise the default is at the end of the visible items. If the toolbar is
+  // in highlighting mode, the item will not be visible until highlighting mode
+  // is exited.
+  void AddItem(const ToolbarItem& item, bool is_component);
+
+  // Removes |item| from the toolbar.  If the toolbar is in highlighting mode,
+  // the item is also removed from the highlighted list (if present).
+  void RemoveItem(const ToolbarItem& item);
+
   // Looks up and returns the extension with the given |id| in the set of
   // enabled extensions.
   const extensions::Extension* GetExtensionById(const std::string& id) const;
diff --git a/chrome/browser/ui/toolbar/toolbar_actions_model_unittest.cc b/chrome/browser/ui/toolbar/toolbar_actions_model_unittest.cc
index c0e7d26..bdf48e8 100644
--- a/chrome/browser/ui/toolbar/toolbar_actions_model_unittest.cc
+++ b/chrome/browser/ui/toolbar/toolbar_actions_model_unittest.cc
@@ -53,7 +53,8 @@
 
  private:
   // ToolbarActionsModel::Observer:
-  void OnToolbarActionAdded(const std::string& id, int index) override {
+  void OnToolbarActionAdded(const ToolbarActionsModel::ToolbarItem& item,
+                            int index) override {
     ++inserted_count_;
   }
 
@@ -1334,11 +1335,24 @@
   EXPECT_EQ(1u, num_toolbar_items());
   EXPECT_EQ(component_action_id(), GetActionIdAtIndex(0u));
 
+  // Just MCA is visible.  Remove MCA.
+  toolbar_model()->RemoveComponentAction(component_action_id());
+  EXPECT_EQ(4u, observer()->removed_count());
+  EXPECT_EQ(0u, num_toolbar_items());
+
+  // Add MCA again.
+  toolbar_model()->AddComponentAction(component_action_id());
+  EXPECT_EQ(1u, num_toolbar_items());
+  EXPECT_EQ(4u, observer()->inserted_count());
+  // Newly added component actions get put at the end of the visible area.
+  EXPECT_EQ(component_action_id(), GetActionIdAtIndex(0u));
+  EXPECT_EQ(1u, toolbar_model()->visible_icon_count());
+  EXPECT_TRUE(toolbar_model()->all_icons_visible());
+
   // Load extension C again.
   ASSERT_TRUE(AddExtension(browser_action_c()));
-  EXPECT_EQ(4u, observer()->inserted_count());
+  EXPECT_EQ(5u, observer()->inserted_count());
   EXPECT_EQ(2u, num_toolbar_items());
-  // Make sure it gets its old spot in the list (at the beginning).
-  EXPECT_EQ(browser_action_c()->id(), GetActionIdAtIndex(0u));
-  EXPECT_EQ(component_action_id(), GetActionIdAtIndex(1u));
+  EXPECT_EQ(component_action_id(), GetActionIdAtIndex(0u));
+  EXPECT_EQ(browser_action_c()->id(), GetActionIdAtIndex(1u));
 }
diff --git a/chrome/browser/ui/views/exclusive_access_bubble_views.cc b/chrome/browser/ui/views/exclusive_access_bubble_views.cc
index d6018160..67636b2 100644
--- a/chrome/browser/ui/views/exclusive_access_bubble_views.cc
+++ b/chrome/browser/ui/views/exclusive_access_bubble_views.cc
@@ -4,7 +4,6 @@
 
 #include "chrome/browser/ui/views/exclusive_access_bubble_views.h"
 
-#include "base/i18n/case_conversion.h"
 #include "base/message_loop/message_loop.h"
 #include "base/strings/string_split.h"
 #include "base/strings/utf_string_conversions.h"
@@ -45,9 +44,12 @@
 // Space between the site info label and the buttons / link.
 const int kMiddlePaddingPx = 30;
 
-// Opacity of the background (out of 255). Only used with
+const int kOuterPaddingHorizPx = 24;
+const int kOuterPaddingVertPx = 8;
+
+// Partially-transparent background color. Only used with
 // IsSimplifiedFullscreenUIEnabled.
-const unsigned char kBackgroundOpacity = 180;
+const SkColor kBackgroundColor = SkColorSetARGB(0xcc, 0x28, 0x2c, 0x32);
 
 class ButtonView : public views::View {
  public:
@@ -113,9 +115,9 @@
 
   // Spacing around the escape key name.
   const int kKeyNameMarginHorizPx = 7;
-  const int kKeyNameBorderPx = 2;
+  const int kKeyNameBorderPx = 1;
   const int kKeyNameCornerRadius = 2;
-  const int kKeyNamePaddingPx = 7;
+  const int kKeyNamePaddingPx = 5;
 
   // The |between_child_spacing| is the horizontal margin of the key name.
   views::BoxLayout* layout = new views::BoxLayout(views::BoxLayout::kHorizontal,
@@ -130,8 +132,7 @@
   if (segments.size() < 3)
     return;
 
-  base::string16 key = base::i18n::ToUpper(segments[1]);
-  views::Label* key_name_label = new views::Label(key, font_list);
+  views::Label* key_name_label = new views::Label(segments[1], font_list);
   key_name_label->SetEnabledColor(foreground_color);
   key_name_label->SetBackgroundColor(background_color);
 
@@ -217,7 +218,7 @@
   ui::NativeTheme* theme = ui::NativeTheme::GetInstanceForWeb();
   SkColor background_color =
       ExclusiveAccessManager::IsSimplifiedFullscreenUIEnabled()
-          ? SkColorSetA(SK_ColorBLACK, kBackgroundOpacity)
+          ? kBackgroundColor
           : theme->GetSystemColor(ui::NativeTheme::kColorId_BubbleBackground);
   SkColor foreground_color =
       ExclusiveAccessManager::IsSimplifiedFullscreenUIEnabled()
@@ -231,17 +232,20 @@
   SetFocusable(false);
 
   ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
-  const gfx::FontList& medium_font_list =
-      rb.GetFontList(ui::ResourceBundle::MediumFont);
+  ui::ResourceBundle::FontStyle font_style =
+      ExclusiveAccessManager::IsSimplifiedFullscreenUIEnabled()
+          ? ui::ResourceBundle::SmallFont
+          : ui::ResourceBundle::MediumFont;
+  const gfx::FontList& font_list = rb.GetFontList(font_style);
 
   if (!ExclusiveAccessManager::IsSimplifiedFullscreenUIEnabled()) {
-    message_label_ = new views::Label(base::string16(), medium_font_list);
+    message_label_ = new views::Label(base::string16(), font_list);
     message_label_->SetEnabledColor(foreground_color);
     message_label_->SetBackgroundColor(background_color);
   }
 
   exit_instruction_ =
-      new InstructionView(bubble_->GetInstructionText(), medium_font_list,
+      new InstructionView(bubble_->GetInstructionText(), font_list,
                           foreground_color, background_color);
 
   link_ = new views::Link();
@@ -251,7 +255,7 @@
   link_->SetText(l10n_util::GetStringUTF16(IDS_EXIT_FULLSCREEN_MODE));
 #endif
   link_->set_listener(this);
-  link_->SetFontList(medium_font_list);
+  link_->SetFontList(font_list);
   link_->SetPressedColor(foreground_color);
   link_->SetEnabledColor(foreground_color);
   link_->SetBackgroundColor(background_color);
@@ -259,16 +263,22 @@
 
   button_view_ = new ButtonView(this, kPaddingPx);
 
+  int outer_padding_horiz = kOuterPaddingHorizPx;
+  int outer_padding_vert = kOuterPaddingVertPx;
   if (!ExclusiveAccessManager::IsSimplifiedFullscreenUIEnabled()) {
     DCHECK(message_label_);
     AddChildView(message_label_);
+
+    outer_padding_horiz = kPaddingPx;
+    outer_padding_vert = kPaddingPx;
   }
   AddChildView(button_view_);
   AddChildView(exit_instruction_);
   AddChildView(link_);
 
-  views::BoxLayout* layout = new views::BoxLayout(
-      views::BoxLayout::kHorizontal, kPaddingPx, kPaddingPx, kMiddlePaddingPx);
+  views::BoxLayout* layout =
+      new views::BoxLayout(views::BoxLayout::kHorizontal, outer_padding_horiz,
+                           outer_padding_vert, kMiddlePaddingPx);
   SetLayoutManager(layout);
 
   UpdateContent(url, bubble_type);
@@ -562,7 +572,10 @@
         bubble_view_context_->GetTopContainerBoundsInScreen().bottom();
   }
   // |desired_top| is the top of the bubble area including the shadow.
-  int desired_top = kPopupTopPx - view_->border()->GetInsets().top();
+  int popup_top = ExclusiveAccessManager::IsSimplifiedFullscreenUIEnabled()
+                      ? kSimplifiedPopupTopPx
+                      : kPopupTopPx;
+  int desired_top = popup_top - view_->border()->GetInsets().top();
   int y = top_container_bottom + desired_top;
 
   if (!ignore_animation_state &&
diff --git a/chrome/browser/ui/views/frame/browser_frame.cc b/chrome/browser/ui/views/frame/browser_frame.cc
index b7283a5..0b3ed94ee 100644
--- a/chrome/browser/ui/views/frame/browser_frame.cc
+++ b/chrome/browser/ui/views/frame/browser_frame.cc
@@ -153,6 +153,10 @@
   return native_browser_frame_->GetWindowPlacement(bounds, show_state);
 }
 
+void BrowserFrame::OnBrowserViewInitViewsComplete() {
+  browser_frame_view_->OnBrowserViewInitViewsComplete();
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 // BrowserFrame, views::Widget overrides:
 
diff --git a/chrome/browser/ui/views/frame/browser_frame.h b/chrome/browser/ui/views/frame/browser_frame.h
index 1ef4802..92bab93 100644
--- a/chrome/browser/ui/views/frame/browser_frame.h
+++ b/chrome/browser/ui/views/frame/browser_frame.h
@@ -96,6 +96,9 @@
   void GetWindowPlacement(gfx::Rect* bounds,
                           ui::WindowShowState* show_state) const;
 
+  // Called when BrowserView creates all it's child views.
+  void OnBrowserViewInitViewsComplete();
+
   // Overridden from views::Widget:
   views::internal::RootView* CreateRootView() override;
   views::NonClientFrameView* CreateNonClientFrameView() override;
diff --git a/chrome/browser/ui/views/frame/browser_frame_mus.cc b/chrome/browser/ui/views/frame/browser_frame_mus.cc
index 6177d1a1..d0ec71f 100644
--- a/chrome/browser/ui/views/frame/browser_frame_mus.cc
+++ b/chrome/browser/ui/views/frame/browser_frame_mus.cc
@@ -64,6 +64,6 @@
 }
 
 void BrowserFrameMus::UpdateClientArea() {
-  window()->SetClientArea(
-      views::WindowManagerFrameValues::instance().normal_insets);
+  // BrowserNonClientFrameViewMus::OnBoundsChanged() takes care of updating
+  // the insets.
 }
diff --git a/chrome/browser/ui/views/frame/browser_frame_mus.h b/chrome/browser/ui/views/frame/browser_frame_mus.h
index db389bc9..4feb827 100644
--- a/chrome/browser/ui/views/frame/browser_frame_mus.h
+++ b/chrome/browser/ui/views/frame/browser_frame_mus.h
@@ -15,6 +15,8 @@
   BrowserFrameMus(BrowserFrame* browser_frame, BrowserView* browser_view);
   ~BrowserFrameMus() override;
 
+  mus::Window* mus_window();
+
  private:
   // Overridden from NativeBrowserFrame:
   views::Widget::InitParams GetWidgetParams() override;
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view.cc
index b99b8af..adb429ea 100644
--- a/chrome/browser/ui/views/frame/browser_non_client_frame_view.cc
+++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view.cc
@@ -61,6 +61,8 @@
   }
 }
 
+void BrowserNonClientFrameView::OnBrowserViewInitViewsComplete() {}
+
 void BrowserNonClientFrameView::UpdateToolbar() {
 }
 
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view.h b/chrome/browser/ui/views/frame/browser_non_client_frame_view.h
index 30abb5938..81344a88 100644
--- a/chrome/browser/ui/views/frame/browser_non_client_frame_view.h
+++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view.h
@@ -41,6 +41,9 @@
   void OnThemeChanged() override;
 #endif
 
+  // Called when BrowserView creates all it's child views.
+  virtual void OnBrowserViewInitViewsComplete();
+
   // Retrieves the bounds, in non-client view coordinates within which the
   // TabStrip should be laid out.
   virtual gfx::Rect GetBoundsForTabStrip(views::View* tabstrip) const = 0;
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_mus.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view_mus.cc
index bac7c90..d030b6c1 100644
--- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_mus.cc
+++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_mus.cc
@@ -14,6 +14,7 @@
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_commands.h"
 #include "chrome/browser/ui/views/frame/browser_frame.h"
+#include "chrome/browser/ui/views/frame/browser_frame_mus.h"
 #include "chrome/browser/ui/views/frame/browser_header_painter_ash.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/browser/ui/views/frame/immersive_mode_controller.h"
@@ -23,6 +24,7 @@
 #include "chrome/browser/ui/views/tab_icon_view.h"
 #include "chrome/browser/ui/views/tabs/tab_strip.h"
 #include "chrome/browser/web_applications/web_app.h"
+#include "components/mus/public/cpp/window.h"
 #include "components/signin/core/common/profile_management_switches.h"
 #include "content/public/browser/web_contents.h"
 #include "extensions/browser/extension_registry.h"
@@ -100,9 +102,15 @@
     BrowserView* browser_view)
     : BrowserNonClientFrameView(frame, browser_view),
       web_app_left_header_view_(nullptr),
-      window_icon_(nullptr) {}
+      window_icon_(nullptr),
+      tab_strip_(nullptr) {}
 
-BrowserNonClientFrameViewMus::~BrowserNonClientFrameViewMus() {}
+BrowserNonClientFrameViewMus::~BrowserNonClientFrameViewMus() {
+  if (tab_strip_) {
+    tab_strip_->RemoveObserver(this);
+    tab_strip_ = nullptr;
+  }
+}
 
 void BrowserNonClientFrameViewMus::Init() {
   // Initializing the TabIconView is expensive, so only do it if we need to.
@@ -119,6 +127,13 @@
 ///////////////////////////////////////////////////////////////////////////////
 // BrowserNonClientFrameView:
 
+void BrowserNonClientFrameViewMus::OnBrowserViewInitViewsComplete() {
+  DCHECK(browser_view()->tabstrip());
+  DCHECK(!tab_strip_);
+  tab_strip_ = browser_view()->tabstrip();
+  tab_strip_->AddObserver(this);
+}
+
 gfx::Rect BrowserNonClientFrameViewMus::GetBoundsForTabStrip(
     views::View* tabstrip) const {
   if (!tabstrip)
@@ -283,6 +298,8 @@
 #endif
 
   BrowserNonClientFrameView::Layout();
+
+  UpdateClientArea();
 }
 
 const char* BrowserNonClientFrameViewMus::GetClassName() const {
@@ -377,7 +394,33 @@
 ///////////////////////////////////////////////////////////////////////////////
 // BrowserNonClientFrameViewMus, private:
 
-// views::NonClientFrameView:
+mus::Window* BrowserNonClientFrameViewMus::mus_window() {
+  return static_cast<BrowserFrameMus*>(frame()->native_widget())->window();
+}
+
+void BrowserNonClientFrameViewMus::UpdateClientArea() {
+  std::vector<gfx::Rect> additional_client_area;
+  if (tab_strip_) {
+    gfx::Rect tab_strip_bounds(GetBoundsForTabStrip(tab_strip_));
+    if (!tab_strip_bounds.IsEmpty() && tab_strip_->max_x()) {
+      tab_strip_bounds.set_width(tab_strip_->max_x());
+      additional_client_area.push_back(tab_strip_bounds);
+    }
+  }
+  mus_window()->SetClientArea(
+      views::WindowManagerFrameValues::instance().normal_insets,
+      additional_client_area);
+}
+
+void BrowserNonClientFrameViewMus::TabStripMaxXChanged(TabStrip* tab_strip) {
+  UpdateClientArea();
+}
+
+void BrowserNonClientFrameViewMus::TabStripDeleted(TabStrip* tab_strip) {
+  tab_strip_->RemoveObserver(this);
+  tab_strip_ = nullptr;
+}
+
 bool BrowserNonClientFrameViewMus::DoesIntersectRect(
     const views::View* target,
     const gfx::Rect& rect) const {
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_mus.h b/chrome/browser/ui/views/frame/browser_non_client_frame_view_mus.h
index d4a3fd2..774a4b3 100644
--- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_mus.h
+++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_mus.h
@@ -9,11 +9,16 @@
 #include "base/memory/scoped_ptr.h"
 #include "chrome/browser/ui/views/frame/browser_non_client_frame_view.h"
 #include "chrome/browser/ui/views/tab_icon_view_model.h"
+#include "chrome/browser/ui/views/tabs/tab_strip_observer.h"
 #include "ui/views/controls/button/button.h"
 
 class TabIconView;
 class WebAppLeftHeaderView;
 
+namespace mus {
+class Window;
+}
+
 namespace views {
 class ImageButton;
 class ToggleImageButton;
@@ -21,7 +26,8 @@
 
 class BrowserNonClientFrameViewMus : public BrowserNonClientFrameView,
                                      public TabIconViewModel,
-                                     public views::ButtonListener {
+                                     public views::ButtonListener,
+                                     public TabStripObserver {
  public:
   static const char kViewClassName[];
 
@@ -31,6 +37,7 @@
   void Init();
 
   // BrowserNonClientFrameView:
+  void OnBrowserViewInitViewsComplete() override;
   gfx::Rect GetBoundsForTabStrip(views::View* tabstrip) const override;
   int GetTopInset(bool restored) const override;
   int GetThemeBackgroundXInset() const override;
@@ -69,6 +76,15 @@
   void UpdateNewAvatarButtonImpl() override;
 
  private:
+  mus::Window* mus_window();
+
+  // Resets the client area on the mus::Window.
+  void UpdateClientArea();
+
+  // TabStripObserver:
+  void TabStripMaxXChanged(TabStrip* tab_strip) override;
+  void TabStripDeleted(TabStrip* tab_strip) override;
+
   // views::NonClientFrameView:
   bool DoesIntersectRect(const views::View* target,
                          const gfx::Rect& rect) const override;
@@ -122,6 +138,8 @@
   // For popups, the window icon.
   TabIconView* window_icon_;
 
+  TabStrip* tab_strip_;
+
   DISALLOW_COPY_AND_ASSIGN(BrowserNonClientFrameViewMus);
 };
 
diff --git a/chrome/browser/ui/views/frame/browser_view.cc b/chrome/browser/ui/views/frame/browser_view.cc
index 08d9722..9769133 100644
--- a/chrome/browser/ui/views/frame/browser_view.cc
+++ b/chrome/browser/ui/views/frame/browser_view.cc
@@ -2164,6 +2164,8 @@
 #endif
 
   GetLocationBar()->GetOmniboxView()->model()->popup_model()->AddObserver(this);
+
+  frame_->OnBrowserViewInitViewsComplete();
 }
 
 void BrowserView::LoadingAnimationCallback() {
diff --git a/chrome/browser/ui/views/infobars/infobar_view.cc b/chrome/browser/ui/views/infobars/infobar_view.cc
index a1ad2e5..c454d42 100644
--- a/chrome/browser/ui/views/infobars/infobar_view.cc
+++ b/chrome/browser/ui/views/infobars/infobar_view.cc
@@ -276,7 +276,7 @@
   // canvas->sk_canvas()->clipPath(fill_path_);
   DCHECK_EQ(total_height(), height())
       << "Infobar piecewise heights do not match overall height";
-  ui::ClipRecorder clip_recorder(context, size());
+  ui::ClipRecorder clip_recorder(context);
   clip_recorder.ClipRect(gfx::Rect(0, arrow_height(), width(), bar_height()));
   views::View::PaintChildren(context);
 }
diff --git a/chrome/browser/ui/views/location_bar/page_action_with_badge_view.cc b/chrome/browser/ui/views/location_bar/page_action_with_badge_view.cc
index 5fee7a65..c0be1c9 100644
--- a/chrome/browser/ui/views/location_bar/page_action_with_badge_view.cc
+++ b/chrome/browser/ui/views/location_bar/page_action_with_badge_view.cc
@@ -21,8 +21,8 @@
 }
 
 gfx::Size PageActionWithBadgeView::GetPreferredSize() const {
-  return gfx::Size(ExtensionAction::kPageActionIconMaxSize,
-                   ExtensionAction::kPageActionIconMaxSize);
+  return gfx::Size(ExtensionAction::ActionIconSize(),
+                   ExtensionAction::ActionIconSize());
 }
 
 void PageActionWithBadgeView::UpdateVisibility(content::WebContents* contents) {
diff --git a/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.cc b/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.cc
index 276ce89..0d1f683a 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.cc
@@ -465,7 +465,7 @@
   contents_bounds.Inset(0, views::NonClientFrameView::kClientEdgeThickness, 0,
                         bottom_shadow_->height() - interior);
 
-  ui::ClipRecorder clip_recorder(context, size());
+  ui::ClipRecorder clip_recorder(context);
   clip_recorder.ClipRect(contents_bounds);
   {
     ui::PaintRecorder recorder(context, size());
diff --git a/chrome/browser/ui/views/profiles/profile_chooser_view.cc b/chrome/browser/ui/views/profiles/profile_chooser_view.cc
index 27d9686b..e7a061ea 100644
--- a/chrome/browser/ui/views/profiles/profile_chooser_view.cc
+++ b/chrome/browser/ui/views/profiles/profile_chooser_view.cc
@@ -327,7 +327,7 @@
 
   void PaintChildren(const ui::PaintContext& context) override {
     // Display any children (the "change photo" overlay) as a circle.
-    ui::ClipRecorder clip_recorder(context, size());
+    ui::ClipRecorder clip_recorder(context);
     clip_recorder.ClipPathWithAntiAliasing(circular_mask_);
     View::PaintChildren(context);
   }
diff --git a/chrome/browser/ui/views/tabs/tab_strip.cc b/chrome/browser/ui/views/tabs/tab_strip.cc
index 52a3e73..3343a38c 100644
--- a/chrome/browser/ui/views/tabs/tab_strip.cc
+++ b/chrome/browser/ui/views/tabs/tab_strip.cc
@@ -2314,7 +2314,10 @@
 
   const int new_tab_x = tabs_.ideal_bounds(tabs_.view_size() - 1).right() -
                         GetLayoutConstant(TABSTRIP_NEW_TAB_BUTTON_OVERLAP);
+  const int old_max_x = newtab_button_bounds_.right();
   newtab_button_bounds_.set_origin(gfx::Point(new_tab_x, 0));
+  if (newtab_button_bounds_.right() != old_max_x)
+    FOR_EACH_OBSERVER(TabStripObserver, observers_, TabStripMaxXChanged(this));
 }
 
 int TabStrip::GenerateIdealBoundsForPinnedTabs(int* first_non_pinned_index) {
diff --git a/chrome/browser/ui/views/tabs/tab_strip.h b/chrome/browser/ui/views/tabs/tab_strip.h
index ec44b678..143a414a 100644
--- a/chrome/browser/ui/views/tabs/tab_strip.h
+++ b/chrome/browser/ui/views/tabs/tab_strip.h
@@ -136,6 +136,10 @@
     return tabs_.ideal_bounds(tab_data_index);
   }
 
+  // Max x-coordinate the tabstrip draws at, which is the right edge of the new
+  // tab button.
+  int max_x() const { return newtab_button_bounds_.right(); }
+
   // Returns the Tab at |index|.
   Tab* tab_at(int index) const { return tabs_.view_at(index); }
 
diff --git a/chrome/browser/ui/views/tabs/tab_strip_observer.cc b/chrome/browser/ui/views/tabs/tab_strip_observer.cc
index 03baafc9..cafb722 100644
--- a/chrome/browser/ui/views/tabs/tab_strip_observer.cc
+++ b/chrome/browser/ui/views/tabs/tab_strip_observer.cc
@@ -17,3 +17,5 @@
 
 void TabStripObserver::TabStripDeleted(TabStrip* tab_strip) {
 }
+
+void TabStripObserver::TabStripMaxXChanged(TabStrip* tab_strip) {}
diff --git a/chrome/browser/ui/views/tabs/tab_strip_observer.h b/chrome/browser/ui/views/tabs/tab_strip_observer.h
index b9dea2e..f36a8461 100644
--- a/chrome/browser/ui/views/tabs/tab_strip_observer.h
+++ b/chrome/browser/ui/views/tabs/tab_strip_observer.h
@@ -37,6 +37,9 @@
   // be dropped.
   virtual void TabStripDeleted(TabStrip* tab_strip);
 
+  // tab_strip->max_x() has changed.
+  virtual void TabStripMaxXChanged(TabStrip* tab_strip);
+
  protected:
   virtual ~TabStripObserver() {}
 };
diff --git a/chrome/browser/ui/views/tabs/window_finder_win.cc b/chrome/browser/ui/views/tabs/window_finder_win.cc
index 63d2f48..79897ff3 100644
--- a/chrome/browser/ui/views/tabs/window_finder_win.cc
+++ b/chrome/browser/ui/views/tabs/window_finder_win.cc
@@ -4,6 +4,8 @@
 
 #include "chrome/browser/ui/views/tabs/window_finder.h"
 
+#include <shobjidl.h>
+
 #include "base/win/scoped_gdi_object.h"
 #include "base/win/windows_version.h"
 #include "ui/aura/window.h"
@@ -150,29 +152,6 @@
 
 // LocalProcessWindowFinder ---------------------------------------------------
 
-// Copied from ShObjIdl.h in 10.0.10240.0 SDK. This can be removed once we
-// update to the newer SDK.
-#if NTDDI_VERSION < 0x0A000000
-class DECLSPEC_UUID("aa509086-5ca9-4c25-8f95-589d3c07b48a")
-    VirtualDesktopManager;
-
-MIDL_INTERFACE("a5cd92ff-29be-454c-8d04-d82879fb3f1b")
-IVirtualDesktopManager : public IUnknown {
- public:
-  virtual HRESULT STDMETHODCALLTYPE IsWindowOnCurrentVirtualDesktop(
-      /* [in] */ __RPC__in HWND topLevelWindow,
-      /* [out] */ __RPC__out BOOL * onCurrentDesktop) = 0;
-
-  virtual HRESULT STDMETHODCALLTYPE GetWindowDesktopId(
-      /* [in] */ __RPC__in HWND topLevelWindow,
-      /* [out] */ __RPC__out GUID * desktopId) = 0;
-
-  virtual HRESULT STDMETHODCALLTYPE MoveWindowToDesktop(
-      /* [in] */ __RPC__in HWND topLevelWindow,
-      /* [in] */ __RPC__in REFGUID desktopId) = 0;
-};
-#endif  // NTDDI_VERSION < 0x0A000000
-
 // Helper class to determine if a particular point contains a window from our
 // process.
 class LocalProcessWindowFinder : public BaseWindowFinder {
diff --git a/chrome/browser/ui/website_settings/website_settings.cc b/chrome/browser/ui/website_settings/website_settings.cc
index a82135a..c717aac 100644
--- a/chrome/browser/ui/website_settings/website_settings.cc
+++ b/chrome/browser/ui/website_settings/website_settings.cc
@@ -30,6 +30,7 @@
 #include "chrome/browser/ssl/chrome_ssl_host_state_delegate_factory.h"
 #include "chrome/browser/ui/website_settings/website_settings_ui.h"
 #include "chrome/common/chrome_switches.h"
+#include "chrome/common/features.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/grit/chromium_strings.h"
@@ -313,7 +314,7 @@
     const GURL& url,
     const SecurityStateModel::SecurityInfo& security_info) {
   bool isChromeUINativeScheme = false;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
   isChromeUINativeScheme = url.SchemeIs(chrome::kChromeUINativeScheme);
 #endif
 
diff --git a/chrome/browser/ui/webui/browsing_history_handler.cc b/chrome/browser/ui/webui/browsing_history_handler.cc
index 1ba3f77..86b83ff 100644
--- a/chrome/browser/ui/webui/browsing_history_handler.cc
+++ b/chrome/browser/ui/webui/browsing_history_handler.cc
@@ -28,6 +28,7 @@
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/chrome_pages.h"
 #include "chrome/browser/ui/webui/favicon_source.h"
+#include "chrome/common/features.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/grit/generated_resources.h"
 #include "components/bookmarks/browser/bookmark_model.h"
@@ -59,7 +60,7 @@
 #include "chrome/browser/supervised_user/supervised_user_url_filter.h"
 #endif
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
 #include "chrome/browser/android/chrome_application.h"
 #endif
 
@@ -544,7 +545,7 @@
 
 void BrowsingHistoryHandler::HandleClearBrowsingData(
     const base::ListValue* args) {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
   chrome::android::ChromeApplication::OpenClearBrowsingData(
       web_ui()->GetWebContents());
 #else
diff --git a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
index ef288e4a..75446090 100644
--- a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
@@ -21,8 +21,6 @@
 #include "chrome/browser/chromeos/login/users/chrome_user_manager.h"
 #include "chrome/browser/chromeos/net/network_portal_detector_impl.h"
 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
-#include "chrome/browser/chromeos/policy/consumer_management_service.h"
-#include "chrome/browser/chromeos/policy/consumer_management_stage.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/chromeos/settings/cros_settings.h"
 #include "chrome/browser/io_thread.h"
@@ -79,7 +77,6 @@
 }
 
 void UpdateAuthParams(base::DictionaryValue* params,
-                      bool is_enrolling_consumer_management,
                       bool is_restrictive_proxy) {
   CrosSettings* cros_settings = CrosSettings::Get();
   bool allow_new_user = true;
@@ -105,10 +102,7 @@
 
   // Now check whether we're in multi-profiles user adding scenario and
   // disable GAIA right panel features if that's the case.
-  // For consumer management enrollment, we also hide all right panel components
-  // and show only an enrollment message.
-  if (UserAddingScreen::Get()->IsRunning() ||
-      is_enrolling_consumer_management) {
+  if (UserAddingScreen::Get()->IsRunning()) {
     params->SetBoolean("createAccount", false);
     params->SetBoolean("guestSignin", false);
     params->SetBoolean("supervisedUsersCanCreate", false);
@@ -166,20 +160,15 @@
 
   // GAPS cookie.
   std::string gaps_cookie;
-
-  // Whether consumer management enrollment is in progress.
-  bool is_enrolling_consumer_management = false;
 };
 
 GaiaScreenHandler::GaiaContext::GaiaContext() {}
 
 GaiaScreenHandler::GaiaScreenHandler(
     CoreOobeActor* core_oobe_actor,
-    const scoped_refptr<NetworkStateInformer>& network_state_informer,
-    policy::ConsumerManagementService* consumer_management)
+    const scoped_refptr<NetworkStateInformer>& network_state_informer)
     : BaseScreenHandler(kJsScreenPath),
       network_state_informer_(network_state_informer),
-      consumer_management_(consumer_management),
       core_oobe_actor_(core_oobe_actor),
       weak_factory_(this) {
   DCHECK(network_state_informer_.get());
@@ -202,8 +191,6 @@
     const GaiaContext& context,
     const std::string& platform_version) {
   base::DictionaryValue params;
-  const bool is_enrolling_consumer_management =
-      context.is_enrolling_consumer_management;
 
   params.SetBoolean("forceReload", context.force_reload);
   params.SetBoolean("isShowUsers", context.show_users);
@@ -211,12 +198,9 @@
   params.SetString("gaiaId", context.gaia_id);
   params.SetBoolean("readOnlyEmail", true);
   params.SetString("email", context.email);
-  params.SetBoolean("isEnrollingConsumerManagement",
-                    is_enrolling_consumer_management);
   params.SetString("gapsCookie", context.gaps_cookie);
 
-  UpdateAuthParams(&params, is_enrolling_consumer_management,
-                   IsRestrictiveProxy());
+  UpdateAuthParams(&params, IsRestrictiveProxy());
 
   if (!context.use_offline) {
     const std::string app_locale = g_browser_process->GetApplicationLocale();
@@ -502,30 +486,7 @@
                                             const std::string& typed_email,
                                             const std::string& password,
                                             bool using_saml) {
-  if (!is_enrolling_consumer_management_) {
-    DoCompleteLogin(gaia_id, typed_email, password, using_saml);
-    return;
-  }
-
-  // Consumer management enrollment is in progress.
-  const std::string owner_email =
-      user_manager::UserManager::Get()->GetOwnerAccountId().GetUserEmail();
-  if (typed_email != owner_email) {
-    // Show Gaia sign-in screen again, since we only allow the owner to sign
-    // in.
-    populated_email_ = owner_email;
-    ShowGaiaAsync(is_enrolling_consumer_management_);
-    return;
-  }
-
-  CHECK(consumer_management_);
-  consumer_management_->SetOwner(owner_email,
-                                 base::Bind(&GaiaScreenHandler::OnSetOwnerDone,
-                                            weak_factory_.GetWeakPtr(),
-                                            gaia_id,
-                                            typed_email,
-                                            password,
-                                            using_saml));
+  DoCompleteLogin(gaia_id, typed_email, password, using_saml);
 }
 
 void GaiaScreenHandler::HandleUsingSAMLAPI() {
@@ -569,25 +530,6 @@
     SubmitLoginFormForTest();
 }
 
-void GaiaScreenHandler::OnSetOwnerDone(const std::string& gaia_id,
-                                       const std::string& typed_email,
-                                       const std::string& password,
-                                       bool using_saml,
-                                       bool success) {
-  CHECK(consumer_management_);
-  if (success) {
-    consumer_management_->SetStage(
-        policy::ConsumerManagementStage::EnrollmentOwnerStored());
-  } else {
-    LOG(ERROR) << "Failed to write owner e-mail to boot lockbox.";
-    consumer_management_->SetStage(
-        policy::ConsumerManagementStage::EnrollmentBootLockboxFailed());
-    // We should continue logging in the user, as there's not much we can do
-    // here.
-  }
-  DoCompleteLogin(gaia_id, typed_email, password, using_saml);
-}
-
 void GaiaScreenHandler::DoCompleteLogin(const std::string& gaia_id,
                                         const std::string& typed_email,
                                         const std::string& password,
@@ -706,8 +648,7 @@
   UMA_HISTOGRAM_BOOLEAN("ChromeOS.SAML.APIUsed", api_used);
 }
 
-void GaiaScreenHandler::ShowGaiaAsync(bool is_enrolling_consumer_management) {
-  is_enrolling_consumer_management_ = is_enrolling_consumer_management;
+void GaiaScreenHandler::ShowGaiaAsync() {
   show_when_dns_and_cookies_cleared_ = true;
   if (gaia_silent_load_ && populated_email_.empty()) {
     dns_cleared_ = true;
@@ -841,7 +782,6 @@
   context.force_reload = force;
   context.use_offline = offline;
   context.email = populated_email_;
-  context.is_enrolling_consumer_management = is_enrolling_consumer_management_;
 
   std::string gaia_id;
   if (!context.email.empty() &&
diff --git a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h
index d404ac51..2e82d52e 100644
--- a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h
@@ -19,10 +19,6 @@
 
 class AccountId;
 
-namespace policy {
-class ConsumerManagementService;
-}
-
 namespace chromeos {
 
 class SigninScreenHandler;
@@ -41,8 +37,7 @@
 
   GaiaScreenHandler(
       CoreOobeActor* core_oobe_actor,
-      const scoped_refptr<NetworkStateInformer>& network_state_informer,
-      policy::ConsumerManagementService* consumer_management);
+      const scoped_refptr<NetworkStateInformer>& network_state_informer);
   ~GaiaScreenHandler() override;
 
   // Decides whether an auth extension should be pre-loaded. If it should,
@@ -112,13 +107,6 @@
 
   void HandleIdentifierEntered(const std::string& account_identifier);
 
-  // This is called when ConsumerManagementService::SetOwner() returns.
-  void OnSetOwnerDone(const std::string& gaia_id,
-                      const std::string& typed_email,
-                      const std::string& password,
-                      bool using_saml,
-                      bool success);
-
   // Really handles the complete login message.
   void DoCompleteLogin(const std::string& gaia_id,
                        const std::string& typed_email,
@@ -153,7 +141,7 @@
   // cleans DNS cache and cookies. In the latter case, the request to show the
   // screen can be canceled by calling CancelShowGaiaAsync() while the clean-up
   // is in progress.
-  void ShowGaiaAsync(bool is_enrolling_consumer_management);
+  void ShowGaiaAsync();
 
   // Cancels the request to show the sign-in screen while the asynchronous
   // clean-up process that precedes the screen showing is in progress.
@@ -211,9 +199,6 @@
   // Network state informer used to keep signin screen up.
   scoped_refptr<NetworkStateInformer> network_state_informer_;
 
-  // Consumer management service for checking if enrollment is in progress.
-  policy::ConsumerManagementService* consumer_management_ = nullptr;
-
   CoreOobeActor* core_oobe_actor_ = nullptr;
 
   // Email to pre-populate with.
@@ -242,9 +227,6 @@
   // API was used.
   bool using_saml_api_ = false;
 
-  // Whether consumer management enrollment is in progress.
-  bool is_enrolling_consumer_management_ = false;
-
   // Test credentials.
   std::string test_user_;
   std::string test_pass_;
diff --git a/chrome/browser/ui/webui/chromeos/login/oobe_ui.cc b/chrome/browser/ui/webui/chromeos/login/oobe_ui.cc
index 5bf9916..287a357 100644
--- a/chrome/browser/ui/webui/chromeos/login/oobe_ui.cc
+++ b/chrome/browser/ui/webui/chromeos/login/oobe_ui.cc
@@ -21,7 +21,6 @@
 #include "chrome/browser/chromeos/login/ui/login_display_host_impl.h"
 #include "chrome/browser/chromeos/login/wizard_controller.h"
 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
-#include "chrome/browser/chromeos/policy/consumer_management_service.h"
 #include "chrome/browser/chromeos/settings/shutdown_policy_handler.h"
 #include "chrome/browser/chromeos/system/input_device_settings.h"
 #include "chrome/browser/extensions/signin/gaia_auth_extension_loader.h"
@@ -307,16 +306,11 @@
   user_image_view_ = user_image_screen_handler;
   AddScreenHandler(user_image_screen_handler);
 
-  policy::ConsumerManagementService* consumer_management =
-      g_browser_process->platform_part()->browser_policy_connector_chromeos()->
-          GetConsumerManagementService();
-
   user_board_screen_handler_ = new UserBoardScreenHandler();
   AddScreenHandler(user_board_screen_handler_);
 
   gaia_screen_handler_ =
-      new GaiaScreenHandler(
-          core_handler_, network_state_informer_, consumer_management);
+      new GaiaScreenHandler(core_handler_, network_state_informer_);
   AddScreenHandler(gaia_screen_handler_);
 
   signin_screen_handler_ =
diff --git a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc
index a1f1a722..4d25dca 100644
--- a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc
@@ -43,8 +43,6 @@
 #include "chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.h"
 #include "chrome/browser/chromeos/login/wizard_controller.h"
 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
-#include "chrome/browser/chromeos/policy/consumer_management_service.h"
-#include "chrome/browser/chromeos/policy/consumer_management_stage.h"
 #include "chrome/browser/chromeos/policy/device_local_account.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/chromeos/settings/cros_settings.h"
@@ -270,13 +268,6 @@
 
   max_mode_delegate_.reset(new TouchViewControllerDelegate());
   max_mode_delegate_->AddObserver(this);
-
-  policy::ConsumerManagementService* consumer_management =
-      g_browser_process->platform_part()->browser_policy_connector_chromeos()->
-          GetConsumerManagementService();
-  is_enrolling_consumer_management_ =
-      consumer_management &&
-      consumer_management->GetStage().IsEnrollmentRequested();
 }
 
 SigninScreenHandler::~SigninScreenHandler() {
@@ -495,8 +486,6 @@
   AddCallback("focusPod", &SigninScreenHandler::HandleFocusPod);
   AddCallback("getPublicSessionKeyboardLayouts",
               &SigninScreenHandler::HandleGetPublicSessionKeyboardLayouts);
-  AddCallback("cancelConsumerManagementEnrollment",
-              &SigninScreenHandler::HandleCancelConsumerManagementEnrollment);
   AddCallback("getTouchViewState",
               &SigninScreenHandler::HandleGetTouchViewState);
   AddCallback("logRemoveUserWarningShown",
@@ -518,14 +507,7 @@
   oobe_ui_ = context.oobe_ui();
 
   std::string email;
-  if (is_enrolling_consumer_management_) {
-    // We don't check if the value of the owner e-mail is trusted because it is
-    // only used to pre-fill the e-mail field in Gaia sign-in page and a cached
-    // value is sufficient.
-    CrosSettings::Get()->GetString(kDeviceOwner, &email);
-  } else {
-    email = context.email();
-  }
+  email = context.email();
   gaia_screen_handler_->set_populated_email(email);
   ShowImpl();
   histogram_helper_->OnScreenShow();
@@ -579,7 +561,7 @@
     GetOobeUI()->AddObserver(this);
   }
 
-  if (oobe_ui_ || is_enrolling_consumer_management_) {
+  if (oobe_ui_) {
     // Shows new user sign-in for OOBE.
     OnShowAddUser();
   } else {
@@ -1285,17 +1267,6 @@
     delegate_->Login(context, specifics);
 }
 
-void SigninScreenHandler::HandleCancelConsumerManagementEnrollment() {
-  policy::ConsumerManagementService* consumer_management =
-      g_browser_process->platform_part()->browser_policy_connector_chromeos()->
-          GetConsumerManagementService();
-  CHECK(consumer_management);
-  consumer_management->SetStage(
-      policy::ConsumerManagementStage::EnrollmentCanceled());
-  is_enrolling_consumer_management_ = false;
-  ShowImpl();
-}
-
 void SigninScreenHandler::HandleGetTouchViewState() {
   if (max_mode_delegate_) {
     CallJS("login.AccountPickerScreen.setTouchViewState",
@@ -1404,7 +1375,7 @@
 
 void SigninScreenHandler::OnShowAddUser() {
   is_account_picker_showing_first_time_ = false;
-  gaia_screen_handler_->ShowGaiaAsync(is_enrolling_consumer_management_);
+  gaia_screen_handler_->ShowGaiaAsync();
 }
 
 net::Error SigninScreenHandler::FrameError() const {
diff --git a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h
index 853fb564..3954a310 100644
--- a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h
@@ -358,7 +358,6 @@
                             bool diagnostic_mode);
   void HandleGetPublicSessionKeyboardLayouts(const AccountId& account_id,
                                              const std::string& locale);
-  void HandleCancelConsumerManagementEnrollment();
   void HandleGetTouchViewState();
   void HandleLogRemoveUserWarningShown();
   void HandleFirstIncorrectPasswordAttempt(const AccountId& account_id);
@@ -472,9 +471,6 @@
   // Maximized mode controller delegate.
   scoped_ptr<TouchViewControllerDelegate> max_mode_delegate_;
 
-  // Whether consumer management enrollment is in progress.
-  bool is_enrolling_consumer_management_ = false;
-
   // Input Method Engine state used at signin screen.
   scoped_refptr<input_method::InputMethodManager::State> ime_state_;
 
diff --git a/chrome/browser/ui/webui/extensions/extensions_ui.cc b/chrome/browser/ui/webui/extensions/extensions_ui.cc
index 2ea97b1..77716c4 100644
--- a/chrome/browser/ui/webui/extensions/extensions_ui.cc
+++ b/chrome/browser/ui/webui/extensions/extensions_ui.cc
@@ -77,6 +77,9 @@
   source->AddResourcePath("item.css", IDR_MD_EXTENSIONS_ITEM_CSS);
   source->AddResourcePath("item.html", IDR_MD_EXTENSIONS_ITEM_HTML);
   source->AddResourcePath("item.js", IDR_MD_EXTENSIONS_ITEM_JS);
+  source->AddResourcePath("item_list.css", IDR_MD_EXTENSIONS_ITEM_LIST_CSS);
+  source->AddResourcePath("item_list.html", IDR_MD_EXTENSIONS_ITEM_LIST_HTML);
+  source->AddResourcePath("item_list.js", IDR_MD_EXTENSIONS_ITEM_LIST_JS);
   source->AddResourcePath("service.html", IDR_MD_EXTENSIONS_SERVICE_HTML);
   source->AddResourcePath("service.js", IDR_MD_EXTENSIONS_SERVICE_JS);
   source->AddResourcePath("sidebar.css", IDR_MD_EXTENSIONS_SIDEBAR_CSS);
diff --git a/chrome/browser/ui/webui/inspect_ui_browsertest.cc b/chrome/browser/ui/webui/inspect_ui_browsertest.cc
index 60458d4..1286acb 100644
--- a/chrome/browser/ui/webui/inspect_ui_browsertest.cc
+++ b/chrome/browser/ui/webui/inspect_ui_browsertest.cc
@@ -68,7 +68,8 @@
       new base::StringValue(kSharedWorkerTestPage)));
 }
 
-IN_PROC_BROWSER_TEST_F(InspectUITest, AndroidTargets) {
+// Flaky due to failure to bind a hardcoded port. crbug.com/566057
+IN_PROC_BROWSER_TEST_F(InspectUITest, DISABLED_AndroidTargets) {
   DevToolsAndroidBridge* android_bridge =
       DevToolsAndroidBridge::Factory::GetForProfile(browser()->profile());
   AndroidDeviceManager::DeviceProviders providers;
diff --git a/chrome/browser/ui/webui/md_downloads/downloads_list_tracker.cc b/chrome/browser/ui/webui/md_downloads/downloads_list_tracker.cc
index b163644..f67a1cb 100644
--- a/chrome/browser/ui/webui/md_downloads/downloads_list_tracker.cc
+++ b/chrome/browser/ui/webui/md_downloads/downloads_list_tracker.cc
@@ -235,14 +235,7 @@
   file_value->SetBoolean("file_externally_removed",
                          download_item->GetFileExternallyRemoved());
   file_value->SetBoolean("resume", download_item->CanResume());
-
-  bool incognito = false;
-  auto* original_manager = GetOriginalNotifierManager();
-  if (original_manager) {
-    incognito =
-        original_manager->GetDownload(download_item->GetId()) == download_item;
-  }
-  file_value->SetBoolean("otr", incognito);
+  file_value->SetBoolean("otr", IsIncognito(*download_item));
 
   const char* danger_type = "";
   base::string16 last_reason_text;
@@ -307,6 +300,11 @@
   return file_value.Pass();
 }
 
+bool DownloadsListTracker::IsIncognito(const DownloadItem& item) const {
+  return GetOriginalNotifierManager() && GetMainNotifierManager() &&
+      GetMainNotifierManager()->GetDownload(item.GetId()) == &item;
+}
+
 const DownloadItem* DownloadsListTracker::GetItemForTesting(size_t index)
     const {
   if (index >= sorted_visible_items_.size())
@@ -335,9 +333,9 @@
   Profile* profile = Profile::FromBrowserContext(
       GetMainNotifierManager()->GetBrowserContext());
   if (profile->IsOffTheRecord()) {
+    Profile* original_profile = profile->GetOriginalProfile();
     original_notifier_.reset(new AllDownloadItemNotifier(
-       BrowserContext::GetDownloadManager(profile->GetOriginalProfile()),
-        this));
+        BrowserContext::GetDownloadManager(original_profile), this));
   }
 
   RebuildSortedSet();
diff --git a/chrome/browser/ui/webui/md_downloads/downloads_list_tracker.h b/chrome/browser/ui/webui/md_downloads/downloads_list_tracker.h
index 05399b3..00c8374 100644
--- a/chrome/browser/ui/webui/md_downloads/downloads_list_tracker.h
+++ b/chrome/browser/ui/webui/md_downloads/downloads_list_tracker.h
@@ -68,6 +68,9 @@
   virtual scoped_ptr<base::DictionaryValue> CreateDownloadItemValue(
       content::DownloadItem* item) const;
 
+  // Exposed for testing.
+  bool IsIncognito(const content::DownloadItem& item) const;
+
   const content::DownloadItem* GetItemForTesting(size_t index) const;
 
  private:
diff --git a/chrome/browser/ui/webui/md_downloads/downloads_list_tracker_unittest.cc b/chrome/browser/ui/webui/md_downloads/downloads_list_tracker_unittest.cc
index 9d279e4..ced1f8f5 100644
--- a/chrome/browser/ui/webui/md_downloads/downloads_list_tracker_unittest.cc
+++ b/chrome/browser/ui/webui/md_downloads/downloads_list_tracker_unittest.cc
@@ -77,6 +77,7 @@
       : DownloadsListTracker(manager, web_ui, base::Bind(&ShouldShowItem)) {}
   ~TestDownloadsListTracker() override {}
 
+  using DownloadsListTracker::IsIncognito;
   using DownloadsListTracker::GetItemForTesting;
 
  protected:
@@ -125,6 +126,7 @@
     tracker_.reset(new TestDownloadsListTracker(manager(), web_ui()));
   }
 
+  TestingProfile* profile() { return &profile_; }
   content::DownloadManager* manager() { return &manager_; }
   content::TestWebUI* web_ui() { return &web_ui_; }
   TestDownloadsListTracker* tracker() { return tracker_.get(); }
@@ -271,3 +273,17 @@
             web_ui()->call_data()[0]->function_name());
   EXPECT_TRUE(GetIds(web_ui()->call_data()[0]->arg2()).empty());
 }
+
+TEST_F(DownloadsListTrackerTest, Incognito) {
+  testing::NiceMock<content::MockDownloadManager> incognito_manager;
+  ON_CALL(incognito_manager, GetBrowserContext()).WillByDefault(Return(
+      TestingProfile::Builder().BuildIncognito(profile())));
+
+  MockDownloadItem item;
+  EXPECT_CALL(item, GetId()).WillRepeatedly(Return(0));
+
+  ON_CALL(incognito_manager, GetDownload(0)).WillByDefault(Return(&item));
+
+  TestDownloadsListTracker tracker(&incognito_manager, web_ui());
+  EXPECT_TRUE(tracker.IsIncognito(item));
+}
diff --git a/chrome/browser/ui/webui/media_router/media_router_webui_message_handler.cc b/chrome/browser/ui/webui/media_router/media_router_webui_message_handler.cc
index 4c911f9..ce1da635 100644
--- a/chrome/browser/ui/webui/media_router/media_router_webui_message_handler.cc
+++ b/chrome/browser/ui/webui/media_router/media_router_webui_message_handler.cc
@@ -53,12 +53,14 @@
     sink_val->SetString("id", sink.id());
     sink_val->SetString("name", sink.name());
     sink_val->SetInteger("iconType", sink.icon_type());
+    if (!sink.description().empty())
+      sink_val->SetString("description", sink.description());
 
     scoped_ptr<base::ListValue> cast_modes_val(new base::ListValue);
     for (MediaCastMode cast_mode : sink_with_cast_modes.cast_modes)
       cast_modes_val->AppendInteger(cast_mode);
-    sink_val->Set("castModes", cast_modes_val.Pass());
 
+    sink_val->Set("castModes", cast_modes_val.Pass());
     value->Append(sink_val.release());
   }
 
@@ -68,14 +70,12 @@
 scoped_ptr<base::DictionaryValue> RouteToValue(
     const MediaRoute& route, const std::string& extension_id) {
   scoped_ptr<base::DictionaryValue> dictionary(new base::DictionaryValue);
-
   dictionary->SetString("id", route.media_route_id());
   dictionary->SetString("sinkId", route.media_sink_id());
   dictionary->SetString("description", route.description());
   dictionary->SetBoolean("isLocal", route.is_local());
 
   const std::string& custom_path = route.custom_controller_path();
-
   if (!custom_path.empty()) {
     std::string full_custom_controller_path = base::StringPrintf("%s://%s/%s",
         extensions::kExtensionScheme, extension_id.c_str(),
diff --git a/chrome/browser/ui/webui/memory_internals/memory_internals_proxy.cc b/chrome/browser/ui/webui/memory_internals/memory_internals_proxy.cc
index dd80abee..5ce9a26e 100644
--- a/chrome/browser/ui/webui/memory_internals/memory_internals_proxy.cc
+++ b/chrome/browser/ui/webui/memory_internals/memory_internals_proxy.cc
@@ -31,6 +31,7 @@
 #include "chrome/browser/ui/browser_iterator.h"
 #include "chrome/browser/ui/tab_contents/tab_contents_iterator.h"
 #include "chrome/browser/ui/webui/memory_internals/memory_internals_handler.h"
+#include "chrome/common/features.h"
 #include "content/public/browser/navigation_controller.h"
 #include "content/public/browser/navigation_entry.h"
 #include "content/public/browser/render_process_host.h"
@@ -82,7 +83,7 @@
 
 void GetAllWebContents(std::set<content::WebContents*>* web_contents) {
   // Add all the existing WebContentses.
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
   for (TabModelList::const_iterator iter = TabModelList::begin();
        iter != TabModelList::end(); ++iter) {
     TabModel* model = *iter;
@@ -223,7 +224,7 @@
 void MemoryInternalsProxy::RequestRendererDetails() {
   renderer_details_->Clear();
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
   for (TabModelList::const_iterator iter = TabModelList::begin();
        iter != TabModelList::end(); ++iter) {
     TabModel* model = *iter;
diff --git a/chrome/browser/ui/webui/net_export_ui.cc b/chrome/browser/ui/webui/net_export_ui.cc
index e5f96ea..f5de774 100644
--- a/chrome/browser/ui/webui/net_export_ui.cc
+++ b/chrome/browser/ui/webui/net_export_ui.cc
@@ -13,6 +13,7 @@
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/common/features.h"
 #include "chrome/common/url_constants.h"
 #include "components/grit/components_resources.h"
 #include "components/net_log/chrome_net_log.h"
@@ -25,7 +26,7 @@
 #include "content/public/browser/web_ui_data_source.h"
 #include "content/public/browser/web_ui_message_handler.h"
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
 #include "chrome/browser/android/intent_helper.h"
 #endif
 
@@ -225,7 +226,7 @@
     return;
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
   std::string email;
   std::string subject = "net_internals_log";
   std::string title = "Issue number: ";
diff --git a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
index fbb0ea8..f2ac65f 100644
--- a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
+++ b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
@@ -272,7 +272,7 @@
   html_source->AddLocalizedString(
       "powerwashDialogTitle", IDS_OPTIONS_FACTORY_RESET_HEADING);
   html_source->AddLocalizedString(
-      "powerwashDialogBody", IDS_OPTIONS_FACTORY_RESET_WARNING);
+      "powerwashDialogExplanation", IDS_OPTIONS_FACTORY_RESET_WARNING);
   html_source->AddLocalizedString(
       "powerwashDialogButton", IDS_RELAUNCH_BUTTON);
   html_source->AddLocalizedString(
@@ -607,14 +607,14 @@
                                   IDS_SETTINGS_SYNC_DISCONNECT_DELETE_PROFILE);
   html_source->AddLocalizedString("syncDisconnectConfirm",
                                   IDS_SETTINGS_SYNC_DISCONNECT_CONFIRM);
+  html_source->AddLocalizedString("manageOtherPeople",
+                                  IDS_SETTINGS_SYNC_MANAGE_OTHER_PEOPLE);
 
   html_source->AddLocalizedString("syncPageTitle", IDS_SETTINGS_SYNC);
   html_source->AddLocalizedString("syncLoading", IDS_SETTINGS_SYNC_LOADING);
   html_source->AddLocalizedString("syncTimeout", IDS_SETTINGS_SYNC_TIMEOUT);
-  html_source->AddLocalizedString("syncEverythingMenuOption",
-                                  IDS_SETTINGS_SYNC_EVERYTHING_MENU_OPTION);
-  html_source->AddLocalizedString("chooseWhatToSyncMenuOption",
-                                  IDS_SETTINGS_CHOOSE_WHAT_TO_SYNC_MENU_OPTION);
+  html_source->AddLocalizedString("syncEverythingCheckboxLabel",
+                                  IDS_SETTINGS_SYNC_EVERYTHING_CHECKBOX_LABEL);
   html_source->AddLocalizedString("appCheckboxLabel",
                                   IDS_SETTINGS_APPS_CHECKBOX_LABEL);
   html_source->AddLocalizedString("extensionsCheckboxLabel",
diff --git a/chrome/browser/ui/webui/settings/md_settings_ui.cc b/chrome/browser/ui/webui/settings/md_settings_ui.cc
index 8417b5ae..88faceb 100644
--- a/chrome/browser/ui/webui/settings/md_settings_ui.cc
+++ b/chrome/browser/ui/webui/settings/md_settings_ui.cc
@@ -46,7 +46,8 @@
   content::WebUIDataSource* html_source =
       content::WebUIDataSource::Create(chrome::kChromeUIMdSettingsHost);
 
-  AddSettingsPageUIHandler(new ResetSettingsHandler(html_source, web_ui));
+  AddSettingsPageUIHandler(ResetSettingsHandler::Create(
+      html_source, Profile::FromWebUI(web_ui)));
 
   // Add all settings resources.
   for (size_t i = 0; i < kSettingsResourcesSize; ++i) {
diff --git a/chrome/browser/ui/webui/settings/reset_settings_handler.cc b/chrome/browser/ui/webui/settings/reset_settings_handler.cc
index 3cc4661..df5b272 100644
--- a/chrome/browser/ui/webui/settings/reset_settings_handler.cc
+++ b/chrome/browser/ui/webui/settings/reset_settings_handler.cc
@@ -43,23 +43,31 @@
 namespace settings {
 
 ResetSettingsHandler::ResetSettingsHandler(
-    content::WebUIDataSource* html_source, content::WebUI* web_ui) {
-  google_brand::GetBrand(&brandcode_);
-  Profile* profile = Profile::FromWebUI(web_ui);
-  resetter_.reset(new ProfileResetter(profile));
-
+    Profile* profile, bool allow_powerwash) : profile_(profile) {
 #if defined(OS_CHROMEOS)
-  policy::BrowserPolicyConnectorChromeOS* connector =
-      g_browser_process->platform_part()->browser_policy_connector_chromeos();
-  allow_powerwash_ = !connector->IsEnterpriseManaged() &&
-      !user_manager::UserManager::Get()->IsLoggedInAsGuest() &&
-      !user_manager::UserManager::Get()->IsLoggedInAsSupervisedUser();
-  html_source->AddBoolean("allowPowerwash", allow_powerwash_);
+  allow_powerwash_ = allow_powerwash;
 #endif  // defined(OS_CHROMEOS)
+  google_brand::GetBrand(&brandcode_);
 }
 
 ResetSettingsHandler::~ResetSettingsHandler() {}
 
+ResetSettingsHandler* ResetSettingsHandler::Create(
+    content::WebUIDataSource* html_source, Profile* profile) {
+  bool allow_powerwash = false;
+#if defined(OS_CHROMEOS)
+  policy::BrowserPolicyConnectorChromeOS* connector =
+      g_browser_process->platform_part()->browser_policy_connector_chromeos();
+  allow_powerwash = !connector->IsEnterpriseManaged() &&
+      !user_manager::UserManager::Get()->IsLoggedInAsGuest() &&
+      !user_manager::UserManager::Get()->IsLoggedInAsSupervisedUser();
+  html_source->AddBoolean("allowPowerwash", allow_powerwash);
+#endif  // defined(OS_CHROMEOS)
+
+  // Inject |allow_powerwash| for testing.
+  return new ResetSettingsHandler(profile, allow_powerwash);
+}
+
 void ResetSettingsHandler::RegisterMessages() {
   web_ui()->RegisterMessageCallback("performResetProfileSettings",
       base::Bind(&ResetSettingsHandler::HandleResetProfileSettings,
@@ -104,14 +112,13 @@
     bool send_feedback) {
   web_ui()->CallJavascriptFunction("SettingsResetPage.doneResetting");
   if (send_feedback && setting_snapshot_) {
-    Profile* profile = Profile::FromWebUI(web_ui());
-    ResettableSettingsSnapshot current_snapshot(profile);
+    ResettableSettingsSnapshot current_snapshot(profile_);
     int difference = setting_snapshot_->FindDifferentFields(current_snapshot);
     if (difference) {
       setting_snapshot_->Subtract(current_snapshot);
       std::string report = SerializeSettingsReport(*setting_snapshot_,
                                                    difference);
-      SendSettingsFeedback(report, profile);
+      SendSettingsFeedback(report, profile_);
     }
   }
   setting_snapshot_.reset();
@@ -119,9 +126,8 @@
 
 void ResetSettingsHandler::OnShowResetProfileDialog(
     const base::ListValue* value) {
-  if (!resetter_->IsActive()) {
-    setting_snapshot_.reset(
-        new ResettableSettingsSnapshot(Profile::FromWebUI(web_ui())));
+  if (!GetResetter()->IsActive()) {
+    setting_snapshot_.reset(new ResettableSettingsSnapshot(profile_));
     setting_snapshot_->RequestShortcuts(base::Bind(
         &ResetSettingsHandler::UpdateFeedbackUI, AsWeakPtr()));
     UpdateFeedbackUI();
@@ -138,7 +144,7 @@
 
 void ResetSettingsHandler::OnHideResetProfileDialog(
     const base::ListValue* value) {
-  if (!resetter_->IsActive())
+  if (!GetResetter()->IsActive())
     setting_snapshot_.reset();
 }
 
@@ -149,8 +155,7 @@
 }
 
 void ResetSettingsHandler::ResetProfile(bool send_settings) {
-  DCHECK(resetter_);
-  DCHECK(!resetter_->IsActive());
+  DCHECK(!GetResetter()->IsActive());
 
   scoped_ptr<BrandcodedDefaultSettings> default_settings;
   if (config_fetcher_) {
@@ -165,7 +170,8 @@
   // installation, use default settings.
   if (!default_settings)
     default_settings.reset(new BrandcodedDefaultSettings);
-  resetter_->Reset(
+
+  GetResetter()->Reset(
       ProfileResetter::ALL,
       default_settings.Pass(),
       base::Bind(&ResetSettingsHandler::OnResetProfileSettingsDone,
@@ -179,14 +185,19 @@
   if (!setting_snapshot_)
     return;
   scoped_ptr<base::ListValue> list = GetReadableFeedbackForSnapshot(
-      Profile::FromWebUI(web_ui()),
-      *setting_snapshot_);
+      profile_, *setting_snapshot_);
   base::DictionaryValue feedback_info;
   feedback_info.Set("feedbackInfo", list.release());
   web_ui()->CallJavascriptFunction(
       "SettingsResetPage.setFeedbackInfo", feedback_info);
 }
 
+ProfileResetter* ResetSettingsHandler::GetResetter() {
+  if (!resetter_)
+    resetter_.reset(new ProfileResetter(profile_));
+  return resetter_.get();
+}
+
 #if defined(OS_CHROMEOS)
 void ResetSettingsHandler::OnShowPowerwashDialog(
      const base::ListValue* args) {
diff --git a/chrome/browser/ui/webui/settings/reset_settings_handler.h b/chrome/browser/ui/webui/settings/reset_settings_handler.h
index 0407947..6238dec 100644
--- a/chrome/browser/ui/webui/settings/reset_settings_handler.h
+++ b/chrome/browser/ui/webui/settings/reset_settings_handler.h
@@ -23,6 +23,7 @@
 }
 
 class BrandcodeConfigFetcher;
+class Profile;
 class ProfileResetter;
 class ResettableSettingsSnapshot;
 
@@ -35,17 +36,24 @@
     : public SettingsPageUIHandler,
       public base::SupportsWeakPtr<ResetSettingsHandler> {
  public:
-  explicit ResetSettingsHandler(
-      content::WebUIDataSource* html_source, content::WebUI* web_ui);
   ~ResetSettingsHandler() override;
 
+  static ResetSettingsHandler* Create(
+      content::WebUIDataSource* html_source, Profile* profile);
+
   // WebUIMessageHandler implementation.
   void RegisterMessages() override;
 
- private:
+ protected:
+  ResetSettingsHandler(Profile* profile, bool allow_powerwash);
+
+  // Overriden in tests to substitute with a test version of ProfileResetter.
+  virtual ProfileResetter* GetResetter();
+
   // Javascript callback to start clearing data.
   void HandleResetProfileSettings(const base::ListValue* value);
 
+ private:
   // Closes the dialog once all requested settings has been reset.
   void OnResetProfileSettingsDone(bool send_feedback);
 
@@ -77,6 +85,8 @@
   bool allow_powerwash_ = false;
 #endif  // defined(OS_CHROMEOS)
 
+  Profile* const profile_;
+
   scoped_ptr<ProfileResetter> resetter_;
 
   scoped_ptr<BrandcodeConfigFetcher> config_fetcher_;
diff --git a/chrome/browser/ui/webui/settings/reset_settings_handler_unittest.cc b/chrome/browser/ui/webui/settings/reset_settings_handler_unittest.cc
new file mode 100644
index 0000000..ea3ee74
--- /dev/null
+++ b/chrome/browser/ui/webui/settings/reset_settings_handler_unittest.cc
@@ -0,0 +1,95 @@
+// 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.
+
+#include "base/values.h"
+#include "chrome/browser/profile_resetter/profile_resetter.h"
+#include "chrome/browser/ui/webui/settings/reset_settings_handler.h"
+#include "chrome/test/base/testing_profile.h"
+#include "content/public/browser/web_ui_data_source.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "content/public/test/test_web_ui.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using settings::ResetSettingsHandler;
+
+namespace {
+
+// Mock version of ProfileResetter to be used in tests.
+class MockProfileResetter : public ProfileResetter {
+ public:
+  explicit MockProfileResetter(TestingProfile* profile)
+      : ProfileResetter(profile) {
+  }
+
+  bool IsActive() const override {
+    return false;
+  }
+
+  void Reset(ResettableFlags resettable_flags,
+             scoped_ptr<BrandcodedDefaultSettings> master_settings,
+             const base::Closure& callback) override {
+    resets_++;
+    callback.Run();
+  }
+
+  size_t resets() const {
+    return resets_;
+  }
+
+ private:
+  size_t resets_ = 0;
+};
+
+class TestingResetSettingsHandler : public ResetSettingsHandler {
+ public:
+  TestingResetSettingsHandler(
+      TestingProfile* profile, bool allow_powerwash, content::WebUI* web_ui)
+      : ResetSettingsHandler(profile, allow_powerwash),
+        resetter_(profile) {
+    set_web_ui(web_ui);
+  }
+
+  size_t resets() const { return resetter_.resets(); }
+
+  using settings::ResetSettingsHandler::HandleResetProfileSettings;
+
+ protected:
+  ProfileResetter* GetResetter() override {
+    return &resetter_;
+  }
+
+private:
+  MockProfileResetter resetter_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestingResetSettingsHandler);
+};
+
+class ResetSettingsHandlerTest : public testing::Test {
+ public:
+  ResetSettingsHandlerTest() : handler_(&profile_, false, &web_ui_) {
+  }
+
+  TestingResetSettingsHandler* handler() { return &handler_; }
+  content::TestWebUI* web_ui() { return &web_ui_; }
+
+ private:
+  // The order here matters.
+  content::TestBrowserThreadBundle thread_bundle_;
+  TestingProfile profile_;
+  content::TestWebUI web_ui_;
+  TestingResetSettingsHandler handler_;
+};
+
+TEST_F(ResetSettingsHandlerTest, HandleResetProfileSettings) {
+  base::ListValue list;
+  list.AppendBoolean(false);
+  handler()->HandleResetProfileSettings(&list);
+  // Check that the delegate ProfileResetter was called.
+  EXPECT_EQ(1u, handler()->resets());
+  // Check that Javascript side is notified after resetting is done.
+  EXPECT_EQ("SettingsResetPage.doneResetting",
+            web_ui()->call_data()[0]->function_name());
+}
+
+}  // namespace
diff --git a/chrome/browser/ui/webui/settings/settings_startup_pages_handler.cc b/chrome/browser/ui/webui/settings/settings_startup_pages_handler.cc
index 316316f..a1a7a67 100644
--- a/chrome/browser/ui/webui/settings/settings_startup_pages_handler.cc
+++ b/chrome/browser/ui/webui/settings/settings_startup_pages_handler.cc
@@ -18,7 +18,8 @@
 }
 
 void StartupPagesHandler::RegisterMessages() {
-  DCHECK(!Profile::FromWebUI(web_ui())->IsOffTheRecord());
+  if (Profile::FromWebUI(web_ui())->IsOffTheRecord())
+    return;
 
   web_ui()->RegisterMessageCallback("setStartupPagesToCurrentPages",
       base::Bind(&StartupPagesHandler::SetStartupPagesToCurrentPages,
diff --git a/chrome/browser/ui/webui/settings/sync_handler.cc b/chrome/browser/ui/webui/settings/sync_handler.cc
index 2292260e..3928f18 100644
--- a/chrome/browser/ui/webui/settings/sync_handler.cc
+++ b/chrome/browser/ui/webui/settings/sync_handler.cc
@@ -19,6 +19,7 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_info_cache.h"
 #include "chrome/browser/profiles/profile_metrics.h"
+#include "chrome/browser/profiles/profile_window.h"
 #include "chrome/browser/signin/chrome_signin_helper.h"
 #include "chrome/browser/signin/signin_error_controller_factory.h"
 #include "chrome/browser/signin/signin_manager_factory.h"
@@ -28,6 +29,7 @@
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/singleton_tabs.h"
+#include "chrome/browser/ui/user_manager.h"
 #include "chrome/browser/ui/webui/options/options_handlers_helper.h"
 #include "chrome/browser/ui/webui/signin/login_ui_service.h"
 #include "chrome/browser/ui/webui/signin/login_ui_service_factory.h"
@@ -222,6 +224,10 @@
   web_ui()->RegisterMessageCallback(
       "SyncSetupGetSyncStatus",
       base::Bind(&SyncHandler::HandleGetSyncStatus, base::Unretained(this)));
+  web_ui()->RegisterMessageCallback(
+      "SyncSetupManageOtherPeople",
+      base::Bind(&SyncHandler::HandleManageOtherPeople,
+                 base::Unretained(this)));
 #if defined(OS_CHROMEOS)
   web_ui()->RegisterMessageCallback(
       "SyncSetupDoSignOutOnAuthError",
@@ -566,6 +572,11 @@
   UpdateSyncState();
 }
 
+void SyncHandler::HandleManageOtherPeople(const base::ListValue* /* args */) {
+  UserManager::Show(base::FilePath(), profiles::USER_MANAGER_NO_TUTORIAL,
+                    profiles::USER_MANAGER_SELECT_PROFILE_NO_ACTION);
+}
+
 void SyncHandler::CloseSyncSetup() {
   // Stop a timer to handle timeout in waiting for checking network connection.
   backend_start_timer_.reset();
diff --git a/chrome/browser/ui/webui/settings/sync_handler.h b/chrome/browser/ui/webui/settings/sync_handler.h
index 9ac84ba..ec67f44 100644
--- a/chrome/browser/ui/webui/settings/sync_handler.h
+++ b/chrome/browser/ui/webui/settings/sync_handler.h
@@ -123,6 +123,7 @@
   void HandleStopSyncing(const base::ListValue* args);
   void HandleCloseTimeout(const base::ListValue* args);
   void HandleGetSyncStatus(const base::ListValue* args);
+  void HandleManageOtherPeople(const base::ListValue* args);
 
 #if !defined(OS_CHROMEOS)
   // Displays the GAIA login form.
diff --git a/chrome/browser_tests.isolate b/chrome/browser_tests.isolate
index 66fbba0c..d90c90aa 100644
--- a/chrome/browser_tests.isolate
+++ b/chrome/browser_tests.isolate
@@ -205,6 +205,7 @@
           '<(PRODUCT_DIR)/chrome_elf.dll',
           '<(PRODUCT_DIR)/clearkeycdm.dll',
           '<(PRODUCT_DIR)/clearkeycdmadapter.dll',
+          '<(PRODUCT_DIR)/crashpad_handler.exe',
           '<(PRODUCT_DIR)/plugins/',
           '<(PRODUCT_DIR)/power_saver_test_plugin.dll',
           '<(PRODUCT_DIR)/ppapi_tests.dll',
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index e76071b8..df433200 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -22,8 +22,600 @@
       'browser/about_flags.h',
       'browser/after_startup_task_utils.cc',
       'browser/after_startup_task_utils.h',
+      'browser/app_controller_mac.h',
+      'browser/app_controller_mac.mm',
+      'browser/app_icon_win.cc',
+      'browser/app_icon_win.h',
+      'browser/app_mode/app_mode_utils.cc',
+      'browser/app_mode/app_mode_utils.h',
+      'browser/autofill/options_util.cc',
+      'browser/autofill/options_util.h',
+      'browser/autofill/personal_data_manager_factory.cc',
+      'browser/autofill/personal_data_manager_factory.h',
+      'browser/autofill/risk_util.cc',
+      'browser/autofill/risk_util.h',
+      'browser/autofill/validation_rules_storage_factory.cc',
+      'browser/autofill/validation_rules_storage_factory.h',
+      'browser/background_sync/background_sync_controller_factory.cc',
+      'browser/background_sync/background_sync_controller_factory.h',
+      'browser/background_sync/background_sync_controller_impl.cc',
+      'browser/background_sync/background_sync_controller_impl.h',
+      'browser/bad_message.cc',
+      'browser/bad_message.h',
+      'browser/banners/app_banner_data_fetcher.cc',
+      'browser/banners/app_banner_data_fetcher.h',
+      'browser/banners/app_banner_debug_log.cc',
+      'browser/banners/app_banner_debug_log.h',
+      'browser/banners/app_banner_manager.cc',
+      'browser/banners/app_banner_manager.h',
+      'browser/banners/app_banner_metrics.cc',
+      'browser/banners/app_banner_metrics.h',
+      'browser/banners/app_banner_settings_helper.cc',
+      'browser/banners/app_banner_settings_helper.h',
+      'browser/bitmap_fetcher/bitmap_fetcher.cc',
+      'browser/bitmap_fetcher/bitmap_fetcher.h',
+      'browser/bitmap_fetcher/bitmap_fetcher_delegate.h',
+      'browser/bitmap_fetcher/bitmap_fetcher_service.cc',
+      'browser/bitmap_fetcher/bitmap_fetcher_service.h',
+      'browser/bitmap_fetcher/bitmap_fetcher_service_factory.cc',
+      'browser/bitmap_fetcher/bitmap_fetcher_service_factory.h',
+      'browser/browser_about_handler.cc',
+      'browser/browser_about_handler.h',
+      'browser/browser_shutdown.cc',
+      'browser/browser_shutdown.h',
+      'browser/browser_util_win.cc',
+      'browser/browser_util_win.h',
+      'browser/browsing_data/autofill_counter.cc',
+      'browser/browsing_data/autofill_counter.h',
+      'browser/browsing_data/browsing_data_appcache_helper.cc',
+      'browser/browsing_data/browsing_data_appcache_helper.h',
+      'browser/browsing_data/browsing_data_cache_storage_helper.cc',
+      'browser/browsing_data/browsing_data_cache_storage_helper.h',
+      'browser/browsing_data/browsing_data_channel_id_helper.cc',
+      'browser/browsing_data/browsing_data_channel_id_helper.h',
+      'browser/browsing_data/browsing_data_cookie_helper.cc',
+      'browser/browsing_data/browsing_data_cookie_helper.h',
+      'browser/browsing_data/browsing_data_counter.cc',
+      'browser/browsing_data/browsing_data_counter.h',
+      'browser/browsing_data/browsing_data_database_helper.cc',
+      'browser/browsing_data/browsing_data_database_helper.h',
+      'browser/browsing_data/browsing_data_file_system_helper.cc',
+      'browser/browsing_data/browsing_data_file_system_helper.h',
+      'browser/browsing_data/browsing_data_helper.cc',
+      'browser/browsing_data/browsing_data_helper.h',
+      'browser/browsing_data/browsing_data_indexed_db_helper.cc',
+      'browser/browsing_data/browsing_data_indexed_db_helper.h',
+      'browser/browsing_data/browsing_data_local_storage_helper.cc',
+      'browser/browsing_data/browsing_data_local_storage_helper.h',
+      'browser/browsing_data/browsing_data_quota_helper.cc',
+      'browser/browsing_data/browsing_data_quota_helper.h',
+      'browser/browsing_data/browsing_data_quota_helper_impl.cc',
+      'browser/browsing_data/browsing_data_quota_helper_impl.h',
+      'browser/browsing_data/browsing_data_remover.cc',
+      'browser/browsing_data/browsing_data_remover.h',
+      'browser/browsing_data/browsing_data_service_worker_helper.cc',
+      'browser/browsing_data/browsing_data_service_worker_helper.h',
+      'browser/browsing_data/cache_counter.cc',
+      'browser/browsing_data/cache_counter.h',
+      'browser/browsing_data/canonical_cookie_hash.cc',
+      'browser/browsing_data/canonical_cookie_hash.h',
+      'browser/browsing_data/cookies_tree_model.cc',
+      'browser/browsing_data/cookies_tree_model.h',
+      'browser/browsing_data/history_counter.cc',
+      'browser/browsing_data/history_counter.h',
+      'browser/browsing_data/local_data_container.cc',
+      'browser/browsing_data/local_data_container.h',
+      'browser/browsing_data/passwords_counter.cc',
+      'browser/browsing_data/passwords_counter.h',
+      'browser/character_encoding.cc',
+      'browser/character_encoding.h',
+      'browser/chrome_browser_application_mac.h',
+      'browser/chrome_browser_application_mac.mm',
+      'browser/chrome_browser_field_trials.cc',
+      'browser/chrome_browser_field_trials.h',
+      'browser/chrome_browser_main.cc',
+      'browser/chrome_browser_main.h',
+      'browser/chrome_browser_main_android.cc',
+      'browser/chrome_browser_main_android.h',
+      'browser/chrome_browser_main_extra_parts.h',
+      'browser/chrome_browser_main_linux.cc',
+      'browser/chrome_browser_main_linux.h',
+      'browser/chrome_browser_main_mac.h',
+      'browser/chrome_browser_main_mac.mm',
+      'browser/chrome_browser_main_win.cc',
+      'browser/chrome_browser_main_win.h',
+      'browser/chrome_child_process_watcher.cc',
+      'browser/chrome_child_process_watcher.h',
+      'browser/chrome_content_browser_client.cc',
+      'browser/chrome_content_browser_client.h',
+      'browser/chrome_content_browser_client_parts.h',
+      'browser/chrome_device_client.cc',
+      'browser/chrome_device_client.h',
+      'browser/chrome_elf_init_win.cc',
+      'browser/chrome_elf_init_win.h',
+      'browser/chrome_net_benchmarking_message_filter.cc',
+      'browser/chrome_net_benchmarking_message_filter.h',
+      'browser/chrome_notification_types.h',
+      'browser/chrome_quota_permission_context.cc',
+      'browser/chrome_quota_permission_context.h',
+      'browser/chrome_select_file_dialog_factory_win.cc',
+      'browser/chrome_select_file_dialog_factory_win.h',
+      'browser/command_observer.h',
+      'browser/command_updater.cc',
+      'browser/command_updater.h',
+      'browser/command_updater_delegate.h',
+      'browser/component_updater/caps_installer_win.cc',
+      'browser/component_updater/caps_installer_win.h',
+      'browser/component_updater/chrome_component_updater_configurator.cc',
+      'browser/component_updater/chrome_component_updater_configurator.h',
+      'browser/component_updater/cld_component_installer.cc',
+      'browser/component_updater/cld_component_installer.h',
+      'browser/component_updater/component_patcher_operation_out_of_process.cc',
+      'browser/component_updater/component_patcher_operation_out_of_process.h',
+      'browser/component_updater/component_updater_resource_throttle.cc',
+      'browser/component_updater/component_updater_resource_throttle.h',
+      'browser/component_updater/ev_whitelist_component_installer.cc',
+      'browser/component_updater/ev_whitelist_component_installer.h',
+      'browser/component_updater/pnacl_component_installer.cc',
+      'browser/component_updater/pnacl_component_installer.h',
+      'browser/component_updater/recovery_component_installer.cc',
+      'browser/component_updater/recovery_component_installer.h',
+      'browser/component_updater/supervised_user_whitelist_installer.cc',
+      'browser/component_updater/supervised_user_whitelist_installer.h',
+      'browser/component_updater/sw_reporter_installer_win.cc',
+      'browser/component_updater/sw_reporter_installer_win.h',
+      'browser/component_updater/swiftshader_component_installer.cc',
+      'browser/component_updater/swiftshader_component_installer.h',
+      'browser/crash_upload_list.cc',
+      'browser/crash_upload_list.h',
+      'browser/custom_handlers/protocol_handler_registry.cc',
+      'browser/custom_handlers/protocol_handler_registry.h',
+      'browser/custom_handlers/protocol_handler_registry_factory.cc',
+      'browser/custom_handlers/protocol_handler_registry_factory.h',
+      'browser/defaults.cc',
+      'browser/defaults.h',
+      'browser/dom_distiller/dom_distiller_service_factory.cc',
+      'browser/dom_distiller/dom_distiller_service_factory.h',
+      'browser/dom_distiller/lazy_dom_distiller_service.cc',
+      'browser/dom_distiller/lazy_dom_distiller_service.h',
+      'browser/dom_distiller/profile_utils.cc',
+      'browser/dom_distiller/profile_utils.h',
+      'browser/dom_distiller/tab_utils.cc',
+      'browser/dom_distiller/tab_utils.h',
+      'browser/domain_reliability/service_factory.cc',
+      'browser/domain_reliability/service_factory.h',
+      'browser/download/all_download_item_notifier.cc',
+      'browser/download/all_download_item_notifier.h',
+      'browser/download/chrome_download_manager_delegate.cc',
+      'browser/download/chrome_download_manager_delegate.h',
+      'browser/download/download_crx_util_android.cc',
+      'browser/download/download_extensions.cc',
+      'browser/download/download_extensions.h',
+      'browser/download/download_file_picker.cc',
+      'browser/download/download_file_picker.h',
+      'browser/download/download_history.cc',
+      'browser/download/download_history.h',
+      'browser/download/download_item_model.cc',
+      'browser/download/download_item_model.h',
+      'browser/download/download_path_reservation_tracker.cc',
+      'browser/download/download_path_reservation_tracker.h',
+      'browser/download/download_prefs.cc',
+      'browser/download/download_prefs.h',
+      'browser/download/download_query.cc',
+      'browser/download/download_query.h',
+      'browser/download/download_request_limiter.cc',
+      'browser/download/download_request_limiter.h',
+      'browser/download/download_resource_throttle.cc',
+      'browser/download/download_resource_throttle.h',
+      'browser/download/download_service.cc',
+      'browser/download/download_service.h',
+      'browser/download/download_service_factory.cc',
+      'browser/download/download_service_factory.h',
+      'browser/download/download_service_impl.cc',
+      'browser/download/download_service_impl.h',
+      'browser/download/download_started_animation.h',
+      'browser/download/download_stats.cc',
+      'browser/download/download_stats.h',
+      'browser/download/download_status_updater.cc',
+      'browser/download/download_status_updater.h',
+      'browser/download/download_status_updater_mac.mm',
+      'browser/download/download_status_updater_win.cc',
+      'browser/download/download_target_determiner.cc',
+      'browser/download/download_target_determiner.h',
+      'browser/download/download_target_determiner_delegate.h',
+      'browser/download/download_target_info.h',
+      'browser/download/download_ui_controller.cc',
+      'browser/download/download_ui_controller.h',
+      'browser/download/drag_download_item.h',
+      'browser/download/save_package_file_picker.cc',
+      'browser/download/save_package_file_picker.h',
+      'browser/enumerate_modules_model_win.cc',
+      'browser/enumerate_modules_model_win.h',
+      # Oh hey, all the cool browser/extensions files are hanging out in
+      # chrome/chrome_browser_extensions.gypi.
+      'browser/external_protocol/external_protocol_handler.cc',
+      'browser/external_protocol/external_protocol_handler.h',
+      'browser/external_protocol/external_protocol_observer.cc',
+      'browser/external_protocol/external_protocol_observer.h',
+      'browser/file_select_helper.cc',
+      'browser/file_select_helper.h',
+      'browser/file_select_helper_mac.mm',
+      'browser/fullscreen.h',
+      'browser/fullscreen_chromeos.cc',
+      'browser/fullscreen_mac.mm',
+      'browser/fullscreen_win.cc',
+      'browser/geolocation/chrome_access_token_store.cc',
+      'browser/geolocation/chrome_access_token_store.h',
+      'browser/geolocation/geolocation_permission_context.cc',
+      'browser/geolocation/geolocation_permission_context.h',
+      'browser/geolocation/geolocation_permission_context_android.cc',
+      'browser/geolocation/geolocation_permission_context_android.h',
+      'browser/geolocation/geolocation_permission_context_extensions.cc',
+      'browser/geolocation/geolocation_permission_context_extensions.h',
+      'browser/geolocation/geolocation_permission_context_factory.cc',
+      'browser/geolocation/geolocation_permission_context_factory.h',
+      'browser/geolocation/geolocation_prefs.cc',
+      'browser/geolocation/geolocation_prefs.h',
+      'browser/global_keyboard_shortcuts_mac.h',
+      'browser/global_keyboard_shortcuts_mac.mm',
+      'browser/gpu/gl_string_manager.cc',
+      'browser/gpu/gl_string_manager.h',
+      'browser/gpu/gpu_feature_checker.cc',
+      'browser/gpu/gpu_feature_checker.h',
+      'browser/gpu/gpu_mode_manager.cc',
+      'browser/gpu/gpu_mode_manager.h',
+      'browser/gpu/three_d_api_observer.cc',
+      'browser/gpu/three_d_api_observer.h',
+      'browser/icon_loader.cc',
+      'browser/icon_loader.h',
+      'browser/icon_loader_android.cc',
+      'browser/icon_loader_chromeos.cc',
+      'browser/icon_loader_mac.mm',
+      'browser/icon_loader_win.cc',
+      'browser/icon_manager.cc',
+      'browser/icon_manager.h',
+      'browser/image_decoder.cc',
+      'browser/image_decoder.h',
+      'browser/image_holder.cc',
+      'browser/image_holder.h',
+      'browser/infobars/infobar_responder.cc',
+      'browser/infobars/infobar_responder.h',
+      'browser/infobars/infobar_service.cc',
+      'browser/infobars/infobar_service.h',
+      'browser/infobars/insecure_content_infobar_delegate.cc',
+      'browser/infobars/insecure_content_infobar_delegate.h',
+      'browser/install_verification/win/imported_module_verification.cc',
+      'browser/install_verification/win/imported_module_verification.h',
+      'browser/install_verification/win/install_verification.cc',
+      'browser/install_verification/win/install_verification.h',
+      'browser/install_verification/win/loaded_module_verification.cc',
+      'browser/install_verification/win/loaded_module_verification.h',
+      'browser/install_verification/win/loaded_modules_snapshot.cc',
+      'browser/install_verification/win/loaded_modules_snapshot.h',
+      'browser/install_verification/win/module_ids.cc',
+      'browser/install_verification/win/module_ids.h',
+      'browser/install_verification/win/module_info.h',
+      'browser/install_verification/win/module_list.cc',
+      'browser/install_verification/win/module_list.h',
+      'browser/install_verification/win/module_verification_common.cc',
+      'browser/install_verification/win/module_verification_common.h',
+      'browser/interests/interests_fetcher.cc',
+      'browser/interests/interests_fetcher.h',
+      'browser/internal_auth.cc',
+      'browser/internal_auth.h',
+      'browser/interstitials/chrome_controller_client.cc',
+      'browser/interstitials/chrome_controller_client.h',
+      'browser/interstitials/chrome_metrics_helper.cc',
+      'browser/interstitials/chrome_metrics_helper.h',
+      'browser/interstitials/security_interstitial_page.cc',
+      'browser/interstitials/security_interstitial_page.h',
+      'browser/intranet_redirect_detector.cc',
+      'browser/intranet_redirect_detector.h',
+      'browser/invalidation/profile_invalidation_provider_factory.cc',
+      'browser/invalidation/profile_invalidation_provider_factory.h',
+      'browser/io_thread.cc',
+      'browser/io_thread.h',
+      'browser/jumplist_updater_win.cc',
+      'browser/jumplist_updater_win.h',
+      'browser/jumplist_win.cc',
+      'browser/jumplist_win.h',
+      'browser/lifetime/application_lifetime.cc',
+      'browser/lifetime/application_lifetime.h',
+      'browser/lifetime/application_lifetime_mac.mm',
+      'browser/lifetime/application_lifetime_win.cc',
+      'browser/mac/bluetooth_utility.h',
+      'browser/mac/bluetooth_utility.mm',
+      'browser/mac/dock.h',
+      'browser/mac/dock.mm',
+      'browser/mac/install_from_dmg.h',
+      'browser/mac/install_from_dmg.mm',
+      'browser/mac/keystone_glue.h',
+      'browser/mac/keystone_glue.mm',
+      'browser/mac/keystone_registration.h',
+      'browser/mac/keystone_registration.mm',
+      'browser/mac/mac_startup_profiler.cc',
+      'browser/mac/mac_startup_profiler.h',
+      'browser/mac/master_prefs.h',
+      'browser/mac/master_prefs.mm',
+      'browser/mac/relauncher.cc',
+      'browser/mac/relauncher.h',
+      'browser/mac/security_wrappers.cc',
+      'browser/mac/security_wrappers.h',
+      'browser/manifest/manifest_icon_downloader.cc',
+      'browser/manifest/manifest_icon_downloader.h',
+      'browser/manifest/manifest_icon_selector.cc',
+      'browser/manifest/manifest_icon_selector.h',
+      'browser/media/desktop_media_list.h',
+      'browser/media/desktop_media_picker.h',
+      'browser/media/desktop_streams_registry.cc',
+      'browser/media/desktop_streams_registry.h',
+      'browser/media/media_access_handler.h',
+      'browser/media/media_capture_devices_dispatcher.cc',
+      'browser/media/media_capture_devices_dispatcher.h',
+      'browser/media/media_device_id_salt.cc',
+      'browser/media/media_device_id_salt.h',
+      'browser/media/media_permission.cc',
+      'browser/media/media_permission.h',
+      'browser/media/media_stream_camera_permission_context_factory.cc',
+      'browser/media/media_stream_camera_permission_context_factory.h',
+      'browser/media/media_stream_capture_indicator.cc',
+      'browser/media/media_stream_capture_indicator.h',
+      'browser/media/media_stream_device_permission_context.cc',
+      'browser/media/media_stream_device_permission_context.h',
+      'browser/media/media_stream_device_permissions.cc',
+      'browser/media/media_stream_device_permissions.h',
+      'browser/media/media_stream_devices_controller.cc',
+      'browser/media/media_stream_devices_controller.h',
+      'browser/media/media_stream_mic_permission_context_factory.cc',
+      'browser/media/media_stream_mic_permission_context_factory.h',
+      'browser/media/media_url_constants.cc',
+      'browser/media/media_url_constants.h',
+      'browser/media/midi_permission_context.cc',
+      'browser/media/midi_permission_context.h',
+      'browser/media/midi_permission_context_factory.cc',
+      'browser/media/midi_permission_context_factory.h',
+      'browser/media/native_desktop_media_list.cc',
+      'browser/media/native_desktop_media_list.h',
+      'browser/media/permission_bubble_media_access_handler.cc',
+      'browser/media/permission_bubble_media_access_handler.h',
+      'browser/media/router/media_router_feature.cc',
+      'browser/media/router/media_router_feature.h',
+      # TODO(brettw) should this go with the webrtc sources?
+      'browser/media/webrtc_log_list.cc',
+      'browser/media/webrtc_log_list.h',
+      'browser/memory_details.cc',
+      'browser/memory_details.h',
+      'browser/memory_details_android.cc',
+      'browser/memory_details_linux.cc',
+      'browser/memory_details_mac.cc',
+      'browser/memory_details_win.cc',
+      'browser/mod_pagespeed/mod_pagespeed_metrics.cc',
+      'browser/mod_pagespeed/mod_pagespeed_metrics.h',
+      'browser/native_window_notification_source.h',
+      'browser/net/predictor_tab_helper.cc',
+      'browser/net/predictor_tab_helper.h',
+      'browser/ntp_snippets/ntp_snippets_service_factory.cc',
+      'browser/ntp_snippets/ntp_snippets_service_factory.h',
+      'browser/page_load_metrics/observers/from_gws_page_load_metrics_observer.cc',
+      'browser/page_load_metrics/observers/from_gws_page_load_metrics_observer.h',
+      'browser/page_load_metrics/observers/google_captcha_observer.cc',
+      'browser/page_load_metrics/observers/google_captcha_observer.h',
+      'browser/page_load_metrics/observers/stale_while_revalidate_metrics_observer.cc',
+      'browser/page_load_metrics/observers/stale_while_revalidate_metrics_observer.h',
+      'browser/page_load_metrics/page_load_metrics_initialize.cc',
+      'browser/page_load_metrics/page_load_metrics_initialize.h',
+      'browser/performance_monitor/performance_monitor.cc',
+      'browser/performance_monitor/performance_monitor.h',
+      'browser/performance_monitor/process_metrics_history.cc',
+      'browser/performance_monitor/process_metrics_history.h',
+      'browser/platform_util.h',
+      'browser/platform_util_chromeos.cc',
+      'browser/platform_util_internal.h',
+      'browser/platform_util_mac.mm',
+      'browser/platform_util_win.cc',
+      'browser/prefetch/prefetch.cc',
+      'browser/prefetch/prefetch.h',
+      'browser/prefetch/prefetch_field_trial.cc',
+      'browser/prefetch/prefetch_field_trial.h',
+      'browser/prerender/prerender_config.cc',
+      'browser/prerender/prerender_config.h',
+      'browser/prerender/prerender_contents.cc',
+      'browser/prerender/prerender_contents.h',
+      'browser/prerender/prerender_field_trial.cc',
+      'browser/prerender/prerender_field_trial.h',
+      'browser/prerender/prerender_final_status.cc',
+      'browser/prerender/prerender_final_status.h',
+      'browser/prerender/prerender_handle.cc',
+      'browser/prerender/prerender_handle.h',
+      'browser/prerender/prerender_histograms.cc',
+      'browser/prerender/prerender_histograms.h',
+      'browser/prerender/prerender_history.cc',
+      'browser/prerender/prerender_history.h',
+      'browser/prerender/prerender_link_manager.cc',
+      'browser/prerender/prerender_link_manager.h',
+      'browser/prerender/prerender_link_manager_factory.cc',
+      'browser/prerender/prerender_link_manager_factory.h',
+      'browser/prerender/prerender_manager.cc',
+      'browser/prerender/prerender_manager.h',
+      'browser/prerender/prerender_manager_factory.cc',
+      'browser/prerender/prerender_manager_factory.h',
+      'browser/prerender/prerender_message_filter.cc',
+      'browser/prerender/prerender_message_filter.h',
+      'browser/prerender/prerender_origin.cc',
+      'browser/prerender/prerender_origin.h',
+      'browser/prerender/prerender_resource_throttle.cc',
+      'browser/prerender/prerender_resource_throttle.h',
+      'browser/prerender/prerender_tab_helper.cc',
+      'browser/prerender/prerender_tab_helper.h',
+      'browser/prerender/prerender_util.cc',
+      'browser/prerender/prerender_util.h',
+      'browser/private_working_set_snapshot.h',
+      'browser/private_working_set_snapshot_win.cc',
+      'browser/process_info_snapshot.h',
+      'browser/process_info_snapshot_mac.cc',
+      'browser/process_resource_usage.cc',
+      'browser/process_resource_usage.h',
+      'browser/process_singleton.h',
+      'browser/process_singleton_win.cc',
+      'browser/push_messaging/push_messaging_app_identifier.cc',
+      'browser/push_messaging/push_messaging_app_identifier.h',
+      'browser/push_messaging/push_messaging_constants.cc',
+      'browser/push_messaging/push_messaging_constants.h',
+      'browser/push_messaging/push_messaging_permission_context.cc',
+      'browser/push_messaging/push_messaging_permission_context.h',
+      'browser/push_messaging/push_messaging_permission_context_factory.cc',
+      'browser/push_messaging/push_messaging_permission_context_factory.h',
+      'browser/push_messaging/push_messaging_service_factory.cc',
+      'browser/push_messaging/push_messaging_service_factory.h',
+      'browser/push_messaging/push_messaging_service_impl.cc',
+      'browser/push_messaging/push_messaging_service_impl.h',
+      'browser/renderer_context_menu/context_menu_content_type_factory.cc',
+      'browser/renderer_context_menu/context_menu_content_type_factory.h',
+      'browser/renderer_context_menu/context_menu_content_type_panel.cc',
+      'browser/renderer_context_menu/context_menu_content_type_panel.h',
+      'browser/renderer_host/chrome_render_message_filter.cc',
+      'browser/renderer_host/chrome_render_message_filter.h',
+      'browser/renderer_host/chrome_render_widget_host_view_mac_delegate.h',
+      'browser/renderer_host/chrome_render_widget_host_view_mac_delegate.mm',
+      'browser/renderer_host/chrome_render_widget_host_view_mac_history_swiper.h',
+      'browser/renderer_host/chrome_render_widget_host_view_mac_history_swiper.mm',
+      'browser/renderer_host/chrome_resource_dispatcher_host_delegate.cc',
+      'browser/renderer_host/chrome_resource_dispatcher_host_delegate.h',
+      'browser/renderer_host/thread_hop_resource_throttle.cc',
+      'browser/renderer_host/thread_hop_resource_throttle.h',
+      'browser/renderer_preferences_util.cc',
+      'browser/renderer_preferences_util.h',
+      'browser/resources_util.cc',
+      'browser/resources_util.h',
+      'browser/safe_browsing/safe_browsing_tab_observer.cc',
+      'browser/safe_browsing/safe_browsing_tab_observer.h',
+      'browser/safe_browsing/srt_fetcher_win.cc',
+      'browser/safe_browsing/srt_fetcher_win.h',
+      'browser/safe_browsing/srt_field_trial_win.cc',
+      'browser/safe_browsing/srt_field_trial_win.h',
+      'browser/safe_browsing/srt_global_error_win.cc',
+      'browser/safe_browsing/srt_global_error_win.h',
+      'browser/search/iframe_source.cc',
+      'browser/search/iframe_source.h',
+      'browser/search/instant_io_context.cc',
+      'browser/search/instant_io_context.h',
+      'browser/search/instant_service.cc',
+      'browser/search/instant_service.h',
+      'browser/search/instant_service_factory.cc',
+      'browser/search/instant_service_factory.h',
+      'browser/search/instant_service_observer.cc',
+      'browser/search/instant_service_observer.h',
+      'browser/search/most_visited_iframe_source.cc',
+      'browser/search/most_visited_iframe_source.h',
+      'browser/search/search.cc',
+      'browser/search/search.h',
+      'browser/search/suggestions/image_fetcher_impl.cc',
+      'browser/search/suggestions/image_fetcher_impl.h',
+      'browser/search/suggestions/suggestions_service_factory.cc',
+      'browser/search/suggestions/suggestions_service_factory.h',
+      'browser/search/suggestions/suggestions_source.cc',
+      'browser/search/suggestions/suggestions_source.h',
+      'browser/search/thumbnail_source.cc',
+      'browser/search/thumbnail_source.h',
+      'browser/shell_integration.cc',
+      'browser/shell_integration.h',
+      'browser/shell_integration_android.cc',
+      'browser/shell_integration_chromeos.cc',
+      'browser/shell_integration_mac.mm',
+      'browser/shell_integration_win.cc',
+      'browser/site_details.cc',
+      'browser/site_details.h',
+      'browser/speech/chrome_speech_recognition_manager_delegate.cc',
+      'browser/speech/chrome_speech_recognition_manager_delegate.h',
+      'browser/speech/tts_android.cc',
+      'browser/speech/tts_android.h',
+      'browser/speech/tts_chromeos.cc',
+      'browser/speech/tts_controller.h',
+      'browser/speech/tts_controller_impl.cc',
+      'browser/speech/tts_controller_impl.h',
+      'browser/speech/tts_mac.mm',
+      'browser/speech/tts_message_filter.cc',
+      'browser/speech/tts_message_filter.h',
+      'browser/speech/tts_platform.cc',
+      'browser/speech/tts_platform.h',
+      'browser/speech/tts_win.cc',
+      'browser/stack_sampling_configuration.cc',
+      'browser/stack_sampling_configuration.h',
+      'browser/status_icons/status_icon.cc',
+      'browser/status_icons/status_icon.h',
+      'browser/status_icons/status_icon_menu_model.cc',
+      'browser/status_icons/status_icon_menu_model.h',
+      'browser/status_icons/status_icon_observer.h',
+      'browser/status_icons/status_tray.cc',
+      'browser/status_icons/status_tray.h',
+      'browser/storage/durable_storage_permission_context.cc',
+      'browser/storage/durable_storage_permission_context.h',
+      'browser/storage/durable_storage_permission_context_factory.cc',
+      'browser/storage/durable_storage_permission_context_factory.h',
+      'browser/tab_contents/navigation_metrics_recorder.cc',
+      'browser/tab_contents/navigation_metrics_recorder.h',
+      'browser/tab_contents/retargeting_details.h',
+      'browser/tab_contents/tab_util.cc',
+      'browser/tab_contents/tab_util.h',
+      'browser/task_management/web_contents_tags.cc',
+      'browser/task_management/web_contents_tags.h',
+      'browser/task_profiler/task_profiler_data_serializer.cc',
+      'browser/task_profiler/task_profiler_data_serializer.h',
+      'browser/thumbnails/content_analysis.cc',
+      'browser/thumbnails/content_analysis.h',
+      'browser/thumbnails/content_based_thumbnailing_algorithm.cc',
+      'browser/thumbnails/content_based_thumbnailing_algorithm.h',
+      'browser/thumbnails/simple_thumbnail_crop.cc',
+      'browser/thumbnails/simple_thumbnail_crop.h',
+      'browser/thumbnails/thumbnail_list_source.cc',
+      'browser/thumbnails/thumbnail_list_source.h',
+      'browser/thumbnails/thumbnail_service.h',
+      'browser/thumbnails/thumbnail_service_factory.cc',
+      'browser/thumbnails/thumbnail_service_factory.h',
+      'browser/thumbnails/thumbnail_service_impl.cc',
+      'browser/thumbnails/thumbnail_service_impl.h',
+      'browser/thumbnails/thumbnail_tab_helper.cc',
+      'browser/thumbnails/thumbnail_tab_helper.h',
+      'browser/thumbnails/thumbnailing_algorithm.h',
+      'browser/thumbnails/thumbnailing_context.cc',
+      'browser/thumbnails/thumbnailing_context.h',
+      'browser/tracing/background_tracing_field_trial.cc',
+      'browser/tracing/background_tracing_field_trial.h',
+      'browser/tracing/crash_service_uploader.cc',
+      'browser/tracing/crash_service_uploader.h',
+      'browser/tracing/navigation_tracing.cc',
+      'browser/tracing/navigation_tracing.h',
+      'browser/translate/chrome_translate_client.cc',
+      'browser/translate/chrome_translate_client.h',
+      'browser/translate/translate_accept_languages_factory.cc',
+      'browser/translate/translate_accept_languages_factory.h',
+      'browser/translate/translate_service.cc',
+      'browser/translate/translate_service.h',
+      'browser/update_client/chrome_update_query_params_delegate.cc',
+      'browser/update_client/chrome_update_query_params_delegate.h',
+      'browser/usb/usb_chooser_context.cc',
+      'browser/usb/usb_chooser_context.h',
+      'browser/usb/usb_chooser_context_factory.cc',
+      'browser/usb/usb_chooser_context_factory.h',
+      'browser/usb/usb_tab_helper.cc',
+      'browser/usb/usb_tab_helper.h',
+      'browser/usb/web_usb_permission_provider.cc',
+      'browser/usb/web_usb_permission_provider.h',
+      'browser/web_data_service_factory.cc',
+      'browser/web_data_service_factory.h',
+    ],
+    # Android sources included regardless of android_java_ui.
+    'chrome_browser_android_sources': [
+      'browser/media/protected_media_identifier_permission_context.cc',
+      'browser/media/protected_media_identifier_permission_context.h',
+      'browser/media/protected_media_identifier_permission_context_factory.cc',
+      'browser/media/protected_media_identifier_permission_context_factory.h',
+    ],
+    # Browser sources used when android_java_ui is enabled.
+    'chrome_browser_android_java_ui_sources': [
       'browser/after_startup_task_utils_android.cc',
       'browser/after_startup_task_utils_android.h',
+      'browser/platform_util_android.cc',
       'browser/android/accessibility/font_size_prefs_android.cc',
       'browser/android/accessibility/font_size_prefs_android.h',
       'browser/android/accessibility_util.cc',
@@ -33,6 +625,8 @@
       'browser/android/android_theme_resources.h',
       'browser/android/appmenu/app_menu_drag_helper.cc',
       'browser/android/appmenu/app_menu_drag_helper.h',
+      'browser/android/background_sync_launcher_android.cc',
+      'browser/android/background_sync_launcher_android.h',
       'browser/android/banners/app_banner_data_fetcher_android.cc',
       'browser/android/banners/app_banner_data_fetcher_android.h',
       'browser/android/banners/app_banner_infobar_delegate_android.cc',
@@ -106,6 +700,8 @@
       'browser/android/data_usage/data_use_tab_helper.h',
       'browser/android/data_usage/data_use_tab_model.cc',
       'browser/android/data_usage/data_use_tab_model.h',
+      'browser/android/data_usage/data_use_tab_ui_manager_android.cc',
+      'browser/android/data_usage/data_use_tab_ui_manager_android.h',
       'browser/android/data_usage/data_use_ui_tab_model.cc',
       'browser/android/data_usage/data_use_ui_tab_model.h',
       'browser/android/data_usage/data_use_ui_tab_model_factory.cc',
@@ -278,341 +874,22 @@
       'browser/android/webapps/single_tab_mode_tab_helper.h',
       'browser/android/webapps/webapp_registry.cc',
       'browser/android/webapps/webapp_registry.h',
-      'browser/app_controller_mac.h',
-      'browser/app_controller_mac.mm',
-      'browser/app_icon_win.cc',
-      'browser/app_icon_win.h',
-      'browser/app_mode/app_mode_utils.cc',
-      'browser/app_mode/app_mode_utils.h',
       'browser/autofill/android/personal_data_manager_android.cc',
       'browser/autofill/android/personal_data_manager_android.h',
-      'browser/autofill/options_util.cc',
-      'browser/autofill/options_util.h',
-      'browser/autofill/personal_data_manager_factory.cc',
-      'browser/autofill/personal_data_manager_factory.h',
-      'browser/autofill/risk_util.cc',
-      'browser/autofill/risk_util.h',
-      'browser/autofill/validation_rules_storage_factory.cc',
-      'browser/autofill/validation_rules_storage_factory.h',
-      'browser/background_sync/background_sync_controller_factory.cc',
-      'browser/background_sync/background_sync_controller_factory.h',
-      'browser/background_sync/background_sync_controller_impl.cc',
-      'browser/background_sync/background_sync_controller_impl.h',
-      'browser/bad_message.cc',
-      'browser/bad_message.h',
-      'browser/banners/app_banner_data_fetcher.cc',
-      'browser/banners/app_banner_data_fetcher.h',
-      'browser/banners/app_banner_debug_log.cc',
-      'browser/banners/app_banner_debug_log.h',
-      'browser/banners/app_banner_manager.cc',
-      'browser/banners/app_banner_manager.h',
-      'browser/banners/app_banner_metrics.cc',
-      'browser/banners/app_banner_metrics.h',
-      'browser/banners/app_banner_settings_helper.cc',
-      'browser/banners/app_banner_settings_helper.h',
-      'browser/bitmap_fetcher/bitmap_fetcher.cc',
-      'browser/bitmap_fetcher/bitmap_fetcher.h',
-      'browser/bitmap_fetcher/bitmap_fetcher_delegate.h',
-      'browser/bitmap_fetcher/bitmap_fetcher_service.cc',
-      'browser/bitmap_fetcher/bitmap_fetcher_service.h',
-      'browser/bitmap_fetcher/bitmap_fetcher_service_factory.cc',
-      'browser/bitmap_fetcher/bitmap_fetcher_service_factory.h',
-      'browser/browser_about_handler.cc',
-      'browser/browser_about_handler.h',
-      'browser/browser_shutdown.cc',
-      'browser/browser_shutdown.h',
-      'browser/browser_util_win.cc',
-      'browser/browser_util_win.h',
-      'browser/browsing_data/autofill_counter.cc',
-      'browser/browsing_data/autofill_counter.h',
-      'browser/browsing_data/browsing_data_appcache_helper.cc',
-      'browser/browsing_data/browsing_data_appcache_helper.h',
-      'browser/browsing_data/browsing_data_cache_storage_helper.cc',
-      'browser/browsing_data/browsing_data_cache_storage_helper.h',
-      'browser/browsing_data/browsing_data_channel_id_helper.cc',
-      'browser/browsing_data/browsing_data_channel_id_helper.h',
-      'browser/browsing_data/browsing_data_cookie_helper.cc',
-      'browser/browsing_data/browsing_data_cookie_helper.h',
-      'browser/browsing_data/browsing_data_counter.cc',
-      'browser/browsing_data/browsing_data_counter.h',
-      'browser/browsing_data/browsing_data_database_helper.cc',
-      'browser/browsing_data/browsing_data_database_helper.h',
-      'browser/browsing_data/browsing_data_file_system_helper.cc',
-      'browser/browsing_data/browsing_data_file_system_helper.h',
-      'browser/browsing_data/browsing_data_helper.cc',
-      'browser/browsing_data/browsing_data_helper.h',
-      'browser/browsing_data/browsing_data_indexed_db_helper.cc',
-      'browser/browsing_data/browsing_data_indexed_db_helper.h',
-      'browser/browsing_data/browsing_data_local_storage_helper.cc',
-      'browser/browsing_data/browsing_data_local_storage_helper.h',
-      'browser/browsing_data/browsing_data_quota_helper.cc',
-      'browser/browsing_data/browsing_data_quota_helper.h',
-      'browser/browsing_data/browsing_data_quota_helper_impl.cc',
-      'browser/browsing_data/browsing_data_quota_helper_impl.h',
-      'browser/browsing_data/browsing_data_remover.cc',
-      'browser/browsing_data/browsing_data_remover.h',
-      'browser/browsing_data/browsing_data_service_worker_helper.cc',
-      'browser/browsing_data/browsing_data_service_worker_helper.h',
-      'browser/browsing_data/cache_counter.cc',
-      'browser/browsing_data/cache_counter.h',
-      'browser/browsing_data/canonical_cookie_hash.cc',
-      'browser/browsing_data/canonical_cookie_hash.h',
-      'browser/browsing_data/cookies_tree_model.cc',
-      'browser/browsing_data/cookies_tree_model.h',
-      'browser/browsing_data/history_counter.cc',
-      'browser/browsing_data/history_counter.h',
-      'browser/browsing_data/local_data_container.cc',
-      'browser/browsing_data/local_data_container.h',
-      'browser/browsing_data/passwords_counter.cc',
-      'browser/browsing_data/passwords_counter.h',
-      'browser/character_encoding.cc',
-      'browser/character_encoding.h',
-      'browser/chrome_browser_application_mac.h',
-      'browser/chrome_browser_application_mac.mm',
-      'browser/chrome_browser_field_trials.cc',
-      'browser/chrome_browser_field_trials.h',
-      'browser/chrome_browser_main.cc',
-      'browser/chrome_browser_main.h',
-      'browser/chrome_browser_main_android.cc',
-      'browser/chrome_browser_main_android.h',
-      'browser/chrome_browser_main_extra_parts.h',
-      'browser/chrome_browser_main_linux.cc',
-      'browser/chrome_browser_main_linux.h',
-      'browser/chrome_browser_main_mac.h',
-      'browser/chrome_browser_main_mac.mm',
-      'browser/chrome_browser_main_win.cc',
-      'browser/chrome_browser_main_win.h',
-      'browser/chrome_child_process_watcher.cc',
-      'browser/chrome_child_process_watcher.h',
-      'browser/chrome_content_browser_client.cc',
-      'browser/chrome_content_browser_client.h',
-      'browser/chrome_content_browser_client_parts.h',
-      'browser/chrome_device_client.cc',
-      'browser/chrome_device_client.h',
-      'browser/chrome_elf_init_win.cc',
-      'browser/chrome_elf_init_win.h',
-      'browser/chrome_net_benchmarking_message_filter.cc',
-      'browser/chrome_net_benchmarking_message_filter.h',
-      'browser/chrome_notification_types.h',
-      'browser/chrome_quota_permission_context.cc',
-      'browser/chrome_quota_permission_context.h',
-      'browser/chrome_select_file_dialog_factory_win.cc',
-      'browser/chrome_select_file_dialog_factory_win.h',
-      'browser/command_observer.h',
-      'browser/command_updater.cc',
-      'browser/command_updater.h',
-      'browser/command_updater_delegate.h',
-      'browser/component_updater/caps_installer_win.cc',
-      'browser/component_updater/caps_installer_win.h',
-      'browser/component_updater/chrome_component_updater_configurator.cc',
-      'browser/component_updater/chrome_component_updater_configurator.h',
-      'browser/component_updater/cld_component_installer.cc',
-      'browser/component_updater/cld_component_installer.h',
-      'browser/component_updater/component_patcher_operation_out_of_process.cc',
-      'browser/component_updater/component_patcher_operation_out_of_process.h',
-      'browser/component_updater/component_updater_resource_throttle.cc',
-      'browser/component_updater/component_updater_resource_throttle.h',
-      'browser/component_updater/ev_whitelist_component_installer.cc',
-      'browser/component_updater/ev_whitelist_component_installer.h',
-      'browser/component_updater/pnacl_component_installer.cc',
-      'browser/component_updater/pnacl_component_installer.h',
-      'browser/component_updater/recovery_component_installer.cc',
-      'browser/component_updater/recovery_component_installer.h',
-      'browser/component_updater/supervised_user_whitelist_installer.cc',
-      'browser/component_updater/supervised_user_whitelist_installer.h',
-      'browser/component_updater/sw_reporter_installer_win.cc',
-      'browser/component_updater/sw_reporter_installer_win.h',
-      'browser/component_updater/swiftshader_component_installer.cc',
-      'browser/component_updater/swiftshader_component_installer.h',
-      'browser/crash_upload_list.cc',
-      'browser/crash_upload_list.h',
-      'browser/custom_handlers/protocol_handler_registry.cc',
-      'browser/custom_handlers/protocol_handler_registry.h',
-      'browser/custom_handlers/protocol_handler_registry_factory.cc',
-      'browser/custom_handlers/protocol_handler_registry_factory.h',
-      'browser/defaults.cc',
-      'browser/defaults.h',
-      'browser/dom_distiller/dom_distiller_service_factory.cc',
-      'browser/dom_distiller/dom_distiller_service_factory.h',
       'browser/dom_distiller/dom_distiller_service_factory_android.cc',
       'browser/dom_distiller/dom_distiller_service_factory_android.h',
-      'browser/dom_distiller/lazy_dom_distiller_service.cc',
-      'browser/dom_distiller/lazy_dom_distiller_service.h',
-      'browser/dom_distiller/profile_utils.cc',
-      'browser/dom_distiller/profile_utils.h',
-      'browser/dom_distiller/tab_utils.cc',
-      'browser/dom_distiller/tab_utils.h',
       'browser/dom_distiller/tab_utils_android.cc',
       'browser/dom_distiller/tab_utils_android.h',
-      'browser/domain_reliability/service_factory.cc',
-      'browser/domain_reliability/service_factory.h',
-      'browser/download/all_download_item_notifier.cc',
-      'browser/download/all_download_item_notifier.h',
-      'browser/download/chrome_download_manager_delegate.cc',
-      'browser/download/chrome_download_manager_delegate.h',
-      'browser/download/download_crx_util_android.cc',
-      'browser/download/download_extensions.cc',
-      'browser/download/download_extensions.h',
-      'browser/download/download_file_picker.cc',
-      'browser/download/download_file_picker.h',
-      'browser/download/download_history.cc',
-      'browser/download/download_history.h',
-      'browser/download/download_item_model.cc',
-      'browser/download/download_item_model.h',
-      'browser/download/download_path_reservation_tracker.cc',
-      'browser/download/download_path_reservation_tracker.h',
-      'browser/download/download_prefs.cc',
-      'browser/download/download_prefs.h',
-      'browser/download/download_query.cc',
-      'browser/download/download_query.h',
-      'browser/download/download_request_limiter.cc',
-      'browser/download/download_request_limiter.h',
-      'browser/download/download_resource_throttle.cc',
-      'browser/download/download_resource_throttle.h',
-      'browser/download/download_service.cc',
-      'browser/download/download_service.h',
-      'browser/download/download_service_factory.cc',
-      'browser/download/download_service_factory.h',
-      'browser/download/download_service_impl.cc',
-      'browser/download/download_service_impl.h',
-      'browser/download/download_started_animation.h',
-      'browser/download/download_stats.cc',
-      'browser/download/download_stats.h',
-      'browser/download/download_status_updater.cc',
-      'browser/download/download_status_updater.h',
-      'browser/download/download_status_updater_mac.mm',
-      'browser/download/download_status_updater_win.cc',
-      'browser/download/download_target_determiner.cc',
-      'browser/download/download_target_determiner.h',
-      'browser/download/download_target_determiner_delegate.h',
-      'browser/download/download_target_info.h',
-      'browser/download/download_ui_controller.cc',
-      'browser/download/download_ui_controller.h',
-      'browser/download/drag_download_item.h',
-      'browser/download/save_package_file_picker.cc',
-      'browser/download/save_package_file_picker.h',
-      'browser/enumerate_modules_model_win.cc',
-      'browser/enumerate_modules_model_win.h',
-      # Oh hey, all the cool browser/extensions files are hanging out in
-      # chrome/chrome_browser_extensions.gypi.
-      'browser/external_protocol/external_protocol_handler.cc',
-      'browser/external_protocol/external_protocol_handler.h',
-      'browser/external_protocol/external_protocol_observer.cc',
-      'browser/external_protocol/external_protocol_observer.h',
-      'browser/file_select_helper.cc',
-      'browser/file_select_helper.h',
-      'browser/file_select_helper_mac.mm',
-      'browser/fullscreen.h',
-      'browser/fullscreen_chromeos.cc',
-      'browser/fullscreen_mac.mm',
-      'browser/fullscreen_win.cc',
-      'browser/geolocation/chrome_access_token_store.cc',
-      'browser/geolocation/chrome_access_token_store.h',
-      'browser/geolocation/geolocation_permission_context.cc',
-      'browser/geolocation/geolocation_permission_context.h',
-      'browser/geolocation/geolocation_permission_context_android.cc',
-      'browser/geolocation/geolocation_permission_context_android.h',
-      'browser/geolocation/geolocation_permission_context_extensions.cc',
-      'browser/geolocation/geolocation_permission_context_extensions.h',
-      'browser/geolocation/geolocation_permission_context_factory.cc',
-      'browser/geolocation/geolocation_permission_context_factory.h',
-      'browser/geolocation/geolocation_prefs.cc',
-      'browser/geolocation/geolocation_prefs.h',
-      'browser/global_keyboard_shortcuts_mac.h',
-      'browser/global_keyboard_shortcuts_mac.mm',
-      'browser/gpu/gl_string_manager.cc',
-      'browser/gpu/gl_string_manager.h',
-      'browser/gpu/gpu_feature_checker.cc',
-      'browser/gpu/gpu_feature_checker.h',
-      'browser/gpu/gpu_mode_manager.cc',
-      'browser/gpu/gpu_mode_manager.h',
-      'browser/gpu/three_d_api_observer.cc',
-      'browser/gpu/three_d_api_observer.h',
-      'browser/icon_loader.cc',
-      'browser/icon_loader.h',
-      'browser/icon_loader_android.cc',
-      'browser/icon_loader_chromeos.cc',
-      'browser/icon_loader_mac.mm',
-      'browser/icon_loader_win.cc',
-      'browser/icon_manager.cc',
-      'browser/icon_manager.h',
-      'browser/image_decoder.cc',
-      'browser/image_decoder.h',
-      'browser/image_holder.cc',
-      'browser/image_holder.h',
-      'browser/infobars/infobar_responder.cc',
-      'browser/infobars/infobar_responder.h',
-      'browser/infobars/infobar_service.cc',
-      'browser/infobars/infobar_service.h',
-      'browser/infobars/insecure_content_infobar_delegate.cc',
-      'browser/infobars/insecure_content_infobar_delegate.h',
-      'browser/install_verification/win/imported_module_verification.cc',
-      'browser/install_verification/win/imported_module_verification.h',
-      'browser/install_verification/win/install_verification.cc',
-      'browser/install_verification/win/install_verification.h',
-      'browser/install_verification/win/loaded_module_verification.cc',
-      'browser/install_verification/win/loaded_module_verification.h',
-      'browser/install_verification/win/loaded_modules_snapshot.cc',
-      'browser/install_verification/win/loaded_modules_snapshot.h',
-      'browser/install_verification/win/module_ids.cc',
-      'browser/install_verification/win/module_ids.h',
-      'browser/install_verification/win/module_info.h',
-      'browser/install_verification/win/module_list.cc',
-      'browser/install_verification/win/module_list.h',
-      'browser/install_verification/win/module_verification_common.cc',
-      'browser/install_verification/win/module_verification_common.h',
+      'browser/download/download_request_infobar_delegate_android.cc',
+      'browser/download/download_request_infobar_delegate_android.h',
+      'browser/geolocation/geolocation_infobar_delegate_android.cc',
+      'browser/geolocation/geolocation_infobar_delegate_android.h',
       'browser/interests/android/interests_service.cc',
       'browser/interests/android/interests_service.h',
-      'browser/interests/interests_fetcher.cc',
-      'browser/interests/interests_fetcher.h',
-      'browser/internal_auth.cc',
-      'browser/internal_auth.h',
-      'browser/interstitials/chrome_controller_client.cc',
-      'browser/interstitials/chrome_controller_client.h',
-      'browser/interstitials/chrome_metrics_helper.cc',
-      'browser/interstitials/chrome_metrics_helper.h',
-      'browser/interstitials/security_interstitial_page.cc',
-      'browser/interstitials/security_interstitial_page.h',
-      'browser/intranet_redirect_detector.cc',
-      'browser/intranet_redirect_detector.h',
       'browser/invalidation/invalidation_service_factory_android.cc',
       'browser/invalidation/invalidation_service_factory_android.h',
-      'browser/invalidation/profile_invalidation_provider_factory.cc',
-      'browser/invalidation/profile_invalidation_provider_factory.h',
-      'browser/io_thread.cc',
-      'browser/io_thread.h',
-      'browser/jumplist_updater_win.cc',
-      'browser/jumplist_updater_win.h',
-      'browser/jumplist_win.cc',
-      'browser/jumplist_win.h',
-      'browser/lifetime/application_lifetime.cc',
-      'browser/lifetime/application_lifetime.h',
       'browser/lifetime/application_lifetime_android.cc',
       'browser/lifetime/application_lifetime_android.h',
-      'browser/lifetime/application_lifetime_mac.mm',
-      'browser/lifetime/application_lifetime_win.cc',
-      'browser/mac/bluetooth_utility.h',
-      'browser/mac/bluetooth_utility.mm',
-      'browser/mac/dock.h',
-      'browser/mac/dock.mm',
-      'browser/mac/install_from_dmg.h',
-      'browser/mac/install_from_dmg.mm',
-      'browser/mac/keystone_glue.h',
-      'browser/mac/keystone_glue.mm',
-      'browser/mac/keystone_registration.h',
-      'browser/mac/keystone_registration.mm',
-      'browser/mac/mac_startup_profiler.cc',
-      'browser/mac/mac_startup_profiler.h',
-      'browser/mac/master_prefs.h',
-      'browser/mac/master_prefs.mm',
-      'browser/mac/relauncher.cc',
-      'browser/mac/relauncher.h',
-      'browser/mac/security_wrappers.cc',
-      'browser/mac/security_wrappers.h',
-      'browser/manifest/manifest_icon_downloader.cc',
-      'browser/manifest/manifest_icon_downloader.h',
-      'browser/manifest/manifest_icon_selector.cc',
-      'browser/manifest/manifest_icon_selector.h',
       'browser/media/android/cdm/media_drm_credential_manager.cc',
       'browser/media/android/cdm/media_drm_credential_manager.h',
       'browser/media/android/remote/record_cast_action.cc',
@@ -625,293 +902,18 @@
       'browser/media/android/router/media_router_android.h',
       'browser/media/android/router/media_router_dialog_controller_android.cc',
       'browser/media/android/router/media_router_dialog_controller_android.h',
-      'browser/media/desktop_media_list.h',
-      'browser/media/desktop_media_picker.h',
-      'browser/media/desktop_streams_registry.cc',
-      'browser/media/desktop_streams_registry.h',
-      'browser/media/media_access_handler.h',
-      'browser/media/media_capture_devices_dispatcher.cc',
-      'browser/media/media_capture_devices_dispatcher.h',
-      'browser/media/media_device_id_salt.cc',
-      'browser/media/media_device_id_salt.h',
-      'browser/media/media_permission.cc',
-      'browser/media/media_permission.h',
-      'browser/media/media_stream_camera_permission_context_factory.cc',
-      'browser/media/media_stream_camera_permission_context_factory.h',
-      'browser/media/media_stream_capture_indicator.cc',
-      'browser/media/media_stream_capture_indicator.h',
-      'browser/media/media_stream_device_permission_context.cc',
-      'browser/media/media_stream_device_permission_context.h',
-      'browser/media/media_stream_device_permissions.cc',
-      'browser/media/media_stream_device_permissions.h',
-      'browser/media/media_stream_devices_controller.cc',
-      'browser/media/media_stream_devices_controller.h',
-      'browser/media/media_stream_mic_permission_context_factory.cc',
-      'browser/media/media_stream_mic_permission_context_factory.h',
-      'browser/media/media_url_constants.cc',
-      'browser/media/media_url_constants.h',
-      'browser/media/midi_permission_context.cc',
-      'browser/media/midi_permission_context.h',
-      'browser/media/midi_permission_context_factory.cc',
-      'browser/media/midi_permission_context_factory.h',
-      'browser/media/native_desktop_media_list.cc',
-      'browser/media/native_desktop_media_list.h',
-      'browser/media/permission_bubble_media_access_handler.cc',
-      'browser/media/permission_bubble_media_access_handler.h',
-      'browser/media/router/media_router_feature.cc',
-      'browser/media/router/media_router_feature.h',
-      # TODO(brettw) should this go with the webrtc sources?
-      'browser/media/webrtc_log_list.cc',
-      'browser/media/webrtc_log_list.h',
-      'browser/memory_details.cc',
-      'browser/memory_details.h',
-      'browser/memory_details_android.cc',
-      'browser/memory_details_linux.cc',
-      'browser/memory_details_mac.cc',
-      'browser/memory_details_win.cc',
-      'browser/mod_pagespeed/mod_pagespeed_metrics.cc',
-      'browser/mod_pagespeed/mod_pagespeed_metrics.h',
-      'browser/native_window_notification_source.h',
-      'browser/net/predictor_tab_helper.cc',
-      'browser/net/predictor_tab_helper.h',
-      'browser/ntp_snippets/ntp_snippets_service_factory.cc',
-      'browser/ntp_snippets/ntp_snippets_service_factory.h',
-      'browser/page_load_metrics/observers/from_gws_page_load_metrics_observer.cc',
-      'browser/page_load_metrics/observers/from_gws_page_load_metrics_observer.h',
-      'browser/page_load_metrics/observers/google_captcha_observer.cc',
-      'browser/page_load_metrics/observers/google_captcha_observer.h',
-      'browser/page_load_metrics/observers/stale_while_revalidate_metrics_observer.cc',
-      'browser/page_load_metrics/observers/stale_while_revalidate_metrics_observer.h',
-      'browser/page_load_metrics/page_load_metrics_initialize.cc',
-      'browser/page_load_metrics/page_load_metrics_initialize.h',
-      'browser/performance_monitor/performance_monitor.cc',
-      'browser/performance_monitor/performance_monitor.h',
-      'browser/performance_monitor/process_metrics_history.cc',
-      'browser/performance_monitor/process_metrics_history.h',
-      'browser/platform_util.h',
-      'browser/platform_util_android.cc',
-      'browser/platform_util_chromeos.cc',
-      'browser/platform_util_internal.h',
-      'browser/platform_util_mac.mm',
-      'browser/platform_util_win.cc',
-      'browser/prefetch/prefetch.cc',
-      'browser/prefetch/prefetch.h',
-      'browser/prefetch/prefetch_field_trial.cc',
-      'browser/prefetch/prefetch_field_trial.h',
-      'browser/prerender/external_prerender_handler_android.cc',
-      'browser/prerender/external_prerender_handler_android.h',
-      'browser/prerender/prerender_config.cc',
-      'browser/prerender/prerender_config.h',
-      'browser/prerender/prerender_contents.cc',
-      'browser/prerender/prerender_contents.h',
-      'browser/prerender/prerender_field_trial.cc',
-      'browser/prerender/prerender_field_trial.h',
-      'browser/prerender/prerender_final_status.cc',
-      'browser/prerender/prerender_final_status.h',
-      'browser/prerender/prerender_handle.cc',
-      'browser/prerender/prerender_handle.h',
-      'browser/prerender/prerender_histograms.cc',
-      'browser/prerender/prerender_histograms.h',
-      'browser/prerender/prerender_history.cc',
-      'browser/prerender/prerender_history.h',
-      'browser/prerender/prerender_link_manager.cc',
-      'browser/prerender/prerender_link_manager.h',
-      'browser/prerender/prerender_link_manager_factory.cc',
-      'browser/prerender/prerender_link_manager_factory.h',
-      'browser/prerender/prerender_manager.cc',
-      'browser/prerender/prerender_manager.h',
-      'browser/prerender/prerender_manager_factory.cc',
-      'browser/prerender/prerender_manager_factory.h',
-      'browser/prerender/prerender_message_filter.cc',
-      'browser/prerender/prerender_message_filter.h',
-      'browser/prerender/prerender_origin.cc',
-      'browser/prerender/prerender_origin.h',
-      'browser/prerender/prerender_resource_throttle.cc',
-      'browser/prerender/prerender_resource_throttle.h',
-      'browser/prerender/prerender_tab_helper.cc',
-      'browser/prerender/prerender_tab_helper.h',
-      'browser/prerender/prerender_util.cc',
-      'browser/prerender/prerender_util.h',
-      'browser/private_working_set_snapshot.h',
-      'browser/private_working_set_snapshot_win.cc',
-      'browser/process_info_snapshot.h',
-      'browser/process_info_snapshot_mac.cc',
-      'browser/process_resource_usage.cc',
-      'browser/process_resource_usage.h',
-      'browser/process_singleton.h',
-      'browser/process_singleton_win.cc',
-      'browser/push_messaging/push_messaging_app_identifier.cc',
-      'browser/push_messaging/push_messaging_app_identifier.h',
-      'browser/push_messaging/push_messaging_constants.cc',
-      'browser/push_messaging/push_messaging_constants.h',
-      'browser/push_messaging/push_messaging_permission_context.cc',
-      'browser/push_messaging/push_messaging_permission_context.h',
-      'browser/push_messaging/push_messaging_permission_context_factory.cc',
-      'browser/push_messaging/push_messaging_permission_context_factory.h',
-      'browser/push_messaging/push_messaging_service_factory.cc',
-      'browser/push_messaging/push_messaging_service_factory.h',
-      'browser/push_messaging/push_messaging_service_impl.cc',
-      'browser/push_messaging/push_messaging_service_impl.h',
-      'browser/renderer_context_menu/context_menu_content_type_factory.cc',
-      'browser/renderer_context_menu/context_menu_content_type_factory.h',
-      'browser/renderer_context_menu/context_menu_content_type_panel.cc',
-      'browser/renderer_context_menu/context_menu_content_type_panel.h',
-      'browser/renderer_host/chrome_render_message_filter.cc',
-      'browser/renderer_host/chrome_render_message_filter.h',
-      'browser/renderer_host/chrome_render_widget_host_view_mac_delegate.h',
-      'browser/renderer_host/chrome_render_widget_host_view_mac_delegate.mm',
-      'browser/renderer_host/chrome_render_widget_host_view_mac_history_swiper.h',
-      'browser/renderer_host/chrome_render_widget_host_view_mac_history_swiper.mm',
-      'browser/renderer_host/chrome_resource_dispatcher_host_delegate.cc',
-      'browser/renderer_host/chrome_resource_dispatcher_host_delegate.h',
-      'browser/renderer_host/thread_hop_resource_throttle.cc',
-      'browser/renderer_host/thread_hop_resource_throttle.h',
-      'browser/renderer_preferences_util.cc',
-      'browser/renderer_preferences_util.h',
-      'browser/resources_util.cc',
-      'browser/resources_util.h',
-      'browser/safe_browsing/safe_browsing_tab_observer.cc',
-      'browser/safe_browsing/safe_browsing_tab_observer.h',
-      'browser/safe_browsing/srt_fetcher_win.cc',
-      'browser/safe_browsing/srt_fetcher_win.h',
-      'browser/safe_browsing/srt_field_trial_win.cc',
-      'browser/safe_browsing/srt_field_trial_win.h',
-      'browser/safe_browsing/srt_global_error_win.cc',
-      'browser/safe_browsing/srt_global_error_win.h',
-      'browser/search/contextual_search_policy_handler_android.cc',
-      'browser/search/contextual_search_policy_handler_android.h',
-      'browser/search/iframe_source.cc',
-      'browser/search/iframe_source.h',
-      'browser/search/instant_io_context.cc',
-      'browser/search/instant_io_context.h',
-      'browser/search/instant_service.cc',
-      'browser/search/instant_service.h',
-      'browser/search/instant_service_factory.cc',
-      'browser/search/instant_service_factory.h',
-      'browser/search/instant_service_observer.cc',
-      'browser/search/instant_service_observer.h',
-      'browser/search/most_visited_iframe_source.cc',
-      'browser/search/most_visited_iframe_source.h',
-      'browser/search/search.cc',
-      'browser/search/search.h',
-      'browser/search/suggestions/image_fetcher_impl.cc',
-      'browser/search/suggestions/image_fetcher_impl.h',
-      'browser/search/suggestions/suggestions_service_factory.cc',
-      'browser/search/suggestions/suggestions_service_factory.h',
-      'browser/search/suggestions/suggestions_source.cc',
-      'browser/search/suggestions/suggestions_source.h',
-      'browser/search/thumbnail_source.cc',
-      'browser/search/thumbnail_source.h',
-      'browser/shell_integration.cc',
-      'browser/shell_integration.h',
-      'browser/shell_integration_android.cc',
-      'browser/shell_integration_chromeos.cc',
-      'browser/shell_integration_mac.mm',
-      'browser/shell_integration_win.cc',
-      'browser/site_details.cc',
-      'browser/site_details.h',
-      'browser/speech/chrome_speech_recognition_manager_delegate.cc',
-      'browser/speech/chrome_speech_recognition_manager_delegate.h',
-      'browser/speech/tts_android.cc',
-      'browser/speech/tts_android.h',
-      'browser/speech/tts_chromeos.cc',
-      'browser/speech/tts_controller.h',
-      'browser/speech/tts_controller_impl.cc',
-      'browser/speech/tts_controller_impl.h',
-      'browser/speech/tts_mac.mm',
-      'browser/speech/tts_message_filter.cc',
-      'browser/speech/tts_message_filter.h',
-      'browser/speech/tts_platform.cc',
-      'browser/speech/tts_platform.h',
-      'browser/speech/tts_win.cc',
-      'browser/stack_sampling_configuration.cc',
-      'browser/stack_sampling_configuration.h',
-      'browser/status_icons/status_icon.cc',
-      'browser/status_icons/status_icon.h',
-      'browser/status_icons/status_icon_menu_model.cc',
-      'browser/status_icons/status_icon_menu_model.h',
-      'browser/status_icons/status_icon_observer.h',
-      'browser/status_icons/status_tray.cc',
-      'browser/status_icons/status_tray.h',
-      'browser/storage/durable_storage_permission_context.cc',
-      'browser/storage/durable_storage_permission_context.h',
-      'browser/storage/durable_storage_permission_context_factory.cc',
-      'browser/storage/durable_storage_permission_context_factory.h',
-      'browser/tab_contents/navigation_metrics_recorder.cc',
-      'browser/tab_contents/navigation_metrics_recorder.h',
-      'browser/tab_contents/retargeting_details.h',
-      'browser/tab_contents/tab_util.cc',
-      'browser/tab_contents/tab_util.h',
-      'browser/task_management/web_contents_tags.cc',
-      'browser/task_management/web_contents_tags.h',
-      'browser/task_profiler/task_profiler_data_serializer.cc',
-      'browser/task_profiler/task_profiler_data_serializer.h',
-      'browser/thumbnails/content_analysis.cc',
-      'browser/thumbnails/content_analysis.h',
-      'browser/thumbnails/content_based_thumbnailing_algorithm.cc',
-      'browser/thumbnails/content_based_thumbnailing_algorithm.h',
-      'browser/thumbnails/simple_thumbnail_crop.cc',
-      'browser/thumbnails/simple_thumbnail_crop.h',
-      'browser/thumbnails/thumbnail_list_source.cc',
-      'browser/thumbnails/thumbnail_list_source.h',
-      'browser/thumbnails/thumbnail_service.h',
-      'browser/thumbnails/thumbnail_service_factory.cc',
-      'browser/thumbnails/thumbnail_service_factory.h',
-      'browser/thumbnails/thumbnail_service_impl.cc',
-      'browser/thumbnails/thumbnail_service_impl.h',
-      'browser/thumbnails/thumbnail_tab_helper.cc',
-      'browser/thumbnails/thumbnail_tab_helper.h',
-      'browser/thumbnails/thumbnailing_algorithm.h',
-      'browser/thumbnails/thumbnailing_context.cc',
-      'browser/thumbnails/thumbnailing_context.h',
-      'browser/tracing/background_tracing_field_trial.cc',
-      'browser/tracing/background_tracing_field_trial.h',
-      'browser/tracing/crash_service_uploader.cc',
-      'browser/tracing/crash_service_uploader.h',
-      'browser/tracing/navigation_tracing.cc',
-      'browser/tracing/navigation_tracing.h',
-      'browser/translate/chrome_translate_client.cc',
-      'browser/translate/chrome_translate_client.h',
-      'browser/translate/translate_accept_languages_factory.cc',
-      'browser/translate/translate_accept_languages_factory.h',
-      'browser/translate/translate_service.cc',
-      'browser/translate/translate_service.h',
-      'browser/update_client/chrome_update_query_params_delegate.cc',
-      'browser/update_client/chrome_update_query_params_delegate.h',
-      'browser/usb/usb_chooser_context.cc',
-      'browser/usb/usb_chooser_context.h',
-      'browser/usb/usb_chooser_context_factory.cc',
-      'browser/usb/usb_chooser_context_factory.h',
-      'browser/usb/usb_tab_helper.cc',
-      'browser/usb/usb_tab_helper.h',
-      'browser/usb/web_usb_permission_provider.cc',
-      'browser/usb/web_usb_permission_provider.h',
-      'browser/web_data_service_factory.cc',
-      'browser/web_data_service_factory.h',
-    ],
-    'chrome_browser_android_sources': [
-      'browser/android/background_sync_launcher_android.cc',
-      'browser/android/background_sync_launcher_android.h',
-      'browser/android/data_usage/data_use_tab_ui_manager_android.cc',
-      'browser/android/data_usage/data_use_tab_ui_manager_android.h',
-      'browser/download/download_request_infobar_delegate_android.cc',
-      'browser/download/download_request_infobar_delegate_android.h',
-      'browser/geolocation/geolocation_infobar_delegate_android.cc',
-      'browser/geolocation/geolocation_infobar_delegate_android.h',
       'browser/media/media_stream_infobar_delegate_android.cc',
       'browser/media/media_stream_infobar_delegate_android.h',
       'browser/media/midi_permission_infobar_delegate_android.cc',
       'browser/media/midi_permission_infobar_delegate_android.h',
       'browser/media/protected_media_identifier_infobar_delegate_android.cc',
       'browser/media/protected_media_identifier_infobar_delegate_android.h',
-      'browser/media/protected_media_identifier_permission_context.cc',
-      'browser/media/protected_media_identifier_permission_context.h',
-      'browser/media/protected_media_identifier_permission_context_factory.cc',
-      'browser/media/protected_media_identifier_permission_context_factory.h',
       'browser/metrics/android_metrics_provider.cc',
       'browser/metrics/android_metrics_provider.h',
       'browser/net/spdyproxy/data_reduction_proxy_infobar_delegate_android.cc',
       'browser/net/spdyproxy/data_reduction_proxy_infobar_delegate_android.h',
+      'browser/net/spdyproxy/data_reduction_proxy_settings_android.cc',
+      'browser/net/spdyproxy/data_reduction_proxy_settings_android.h',
       'browser/password_manager/account_chooser_dialog_android.cc',
       'browser/password_manager/account_chooser_dialog_android.h',
       'browser/password_manager/auto_signin_first_run_infobar_delegate.cc',
@@ -924,6 +926,12 @@
       'browser/permissions/permission_queue_controller.h',
       'browser/precache/precache_manager_factory.cc',
       'browser/precache/precache_manager_factory.h',
+      'browser/prerender/external_prerender_handler_android.cc',
+      'browser/prerender/external_prerender_handler_android.h',
+      'browser/profiles/profile_android.cc',
+      'browser/profiles/profile_android.h',
+      'browser/search/contextual_search_policy_handler_android.cc',
+      'browser/search/contextual_search_policy_handler_android.h',
       'browser/signin/oauth2_token_service_delegate_android.cc',
       'browser/signin/oauth2_token_service_delegate_android.h',
       'browser/ssl/ssl_add_certificate_android.cc',
@@ -1730,14 +1738,6 @@
       'browser/google/google_url_tracker_factory.h',
     ],
     'chrome_browser_history_sources': [
-      'browser/history/android/android_history_provider_service.cc',
-      'browser/history/android/android_history_provider_service.h',
-      'browser/history/android/android_provider_backend.cc',
-      'browser/history/android/android_provider_backend.h',
-      'browser/history/android/bookmark_model_sql_handler.cc',
-      'browser/history/android/bookmark_model_sql_handler.h',
-      'browser/history/android/sqlite_cursor.cc',
-      'browser/history/android/sqlite_cursor.h',
       'browser/history/chrome_history_backend_client.cc',
       'browser/history/chrome_history_backend_client.h',
       'browser/history/chrome_history_client.cc',
@@ -1753,6 +1753,17 @@
       'browser/history/web_history_service_factory.cc',
       'browser/history/web_history_service_factory.h',
     ],
+    # History sources used when android_java_ui is enabled.
+    'chrome_browser_history_android_java_ui_sources': [
+      'browser/history/android/android_history_provider_service.cc',
+      'browser/history/android/android_history_provider_service.h',
+      'browser/history/android/android_provider_backend.cc',
+      'browser/history/android/android_provider_backend.h',
+      'browser/history/android/bookmark_model_sql_handler.cc',
+      'browser/history/android/bookmark_model_sql_handler.h',
+      'browser/history/android/sqlite_cursor.cc',
+      'browser/history/android/sqlite_cursor.h',
+    ],
     'chrome_browser_jni_sources': [
       'android/java/src/org/chromium/chrome/browser/AfterStartupTaskUtils.java',
       'android/java/src/org/chromium/chrome/browser/ApplicationLifetime.java',
@@ -2006,8 +2017,6 @@
       'browser/net/spdyproxy/data_reduction_proxy_chrome_settings.h',
       'browser/net/spdyproxy/data_reduction_proxy_chrome_settings_factory.cc',
       'browser/net/spdyproxy/data_reduction_proxy_chrome_settings_factory.h',
-      'browser/net/spdyproxy/data_reduction_proxy_settings_android.cc',
-      'browser/net/spdyproxy/data_reduction_proxy_settings_android.h',
       'browser/net/timed_cache.cc',
       'browser/net/timed_cache.h',
       'browser/net/url_info.cc',
@@ -2029,8 +2038,6 @@
       'browser/notifications/notification_permission_context_factory.cc',
       'browser/notifications/notification_permission_context_factory.h',
       'browser/notifications/notification_ui_manager.h',
-      'browser/notifications/notification_ui_manager_android.cc',
-      'browser/notifications/notification_ui_manager_android.h',
       'browser/notifications/notifier_state_tracker.cc',
       'browser/notifications/notifier_state_tracker.h',
       'browser/notifications/notifier_state_tracker_factory.cc',
@@ -2044,8 +2051,10 @@
       'browser/push_messaging/push_messaging_notification_manager.cc',
       'browser/push_messaging/push_messaging_notification_manager.h',
     ],
-    # Used on Android when notifications are enabled.
-    'chrome_browser_notifications_android_sources': [
+    # Used on Android when notifications and java_ui are enabled.
+    'chrome_browser_notifications_android_java_ui_sources': [
+      'browser/notifications/notification_ui_manager_android.cc',
+      'browser/notifications/notification_ui_manager_android.h',
       'browser/notifications/notification_permission_infobar_delegate.cc',
       'browser/notifications/notification_permission_infobar_delegate.h',
     ],
@@ -2126,11 +2135,14 @@
       'browser/permissions/permission_request_id.h',
       'browser/permissions/permission_uma_util.cc',
       'browser/permissions/permission_uma_util.h',
-      'browser/permissions/permission_update_infobar_delegate_android.cc',
-      'browser/permissions/permission_update_infobar_delegate_android.h',
       'browser/permissions/permission_util.cc',
       'browser/permissions/permission_util.h',
     ],
+    # Permissions sources used when android_java_ui is enabled.
+    'chrome_browser_permissions_android_java_ui_sources': [
+      'browser/permissions/permission_update_infobar_delegate_android.cc',
+      'browser/permissions/permission_update_infobar_delegate_android.h',
+    ],
     # See also the plugin_installation_sources list below.
     'chrome_browser_plugins_sources': [
       'browser/browsing_data/browsing_data_flash_lso_helper.cc',
@@ -2407,8 +2419,6 @@
       'browser/profiles/off_the_record_profile_io_data.h',
       'browser/profiles/profile.cc',
       'browser/profiles/profile.h',
-      'browser/profiles/profile_android.cc',
-      'browser/profiles/profile_android.h',
       'browser/profiles/profile_attributes_entry.cc',
       'browser/profiles/profile_attributes_entry.h',
       'browser/profiles/profile_attributes_storage.h',
@@ -2606,8 +2616,6 @@
       'browser/search_engines/search_provider_install_state_message_filter.h',
       'browser/search_engines/template_url_fetcher_factory.cc',
       'browser/search_engines/template_url_fetcher_factory.h',
-      'browser/search_engines/template_url_service_android.cc',
-      'browser/search_engines/template_url_service_android.h',
       'browser/search_engines/template_url_service_factory.cc',
       'browser/search_engines/template_url_service_factory.h',
       'browser/search_engines/ui_thread_search_terms_data.cc',
@@ -2615,6 +2623,11 @@
       'browser/search_engines/ui_thread_search_terms_data_android.cc',
       'browser/search_engines/ui_thread_search_terms_data_android.h',
     ],
+    # Search sources used when android_java_ui is enabled.
+    'chrome_browser_search_engines_android_java_ui_sources': [
+      'browser/search_engines/template_url_service_android.cc',
+      'browser/search_engines/template_url_service_android.h',
+    ],
     'chrome_browser_service_discovery_sources': [
       'browser/local_discovery/cloud_device_list.cc',
       'browser/local_discovery/cloud_device_list.h',
@@ -2792,8 +2805,6 @@
       'browser/ssl/common_name_mismatch_handler.h',
       'browser/ssl/security_state_model.cc',
       'browser/ssl/security_state_model.h',
-      'browser/ssl/security_state_model_android.cc',
-      'browser/ssl/security_state_model_android.h',
       'browser/ssl/security_state_model_client.h',
       'browser/ssl/ssl_blocking_page.cc',
       'browser/ssl/ssl_blocking_page.h',
@@ -2802,15 +2813,16 @@
       'browser/ssl/ssl_error_handler.cc',
       'browser/ssl/ssl_error_handler.h',
     ],
+    # SSL sources used when android_java_ui is enabled.
+    'chrome_browser_ssl_android_java_ui_sources': [
+      'browser/ssl/security_state_model_android.cc',
+      'browser/ssl/security_state_model_android.h',
+    ],
     'chrome_browser_supervised_user_sources': [
       'browser/content_settings/content_settings_supervised_provider.cc',
       'browser/content_settings/content_settings_supervised_provider.h',
-      'browser/supervised_user/child_accounts/child_account_feedback_reporter_android.cc',
-      'browser/supervised_user/child_accounts/child_account_feedback_reporter_android.h',
       'browser/supervised_user/child_accounts/child_account_service.cc',
       'browser/supervised_user/child_accounts/child_account_service.h',
-      'browser/supervised_user/child_accounts/child_account_service_android.cc',
-      'browser/supervised_user/child_accounts/child_account_service_android.h',
       'browser/supervised_user/child_accounts/child_account_service_factory.cc',
       'browser/supervised_user/child_accounts/child_account_service_factory.h',
       'browser/supervised_user/child_accounts/family_info_fetcher.cc',
@@ -2855,6 +2867,13 @@
       'browser/supervised_user/supervised_user_whitelist_service.h',
       'browser/supervised_user/supervised_users.h',
     ],
+    # Child accounts sources used with android_java_ui enabled.
+    'chrome_browser_supervised_user_android_java_ui_sources': [
+      'browser/supervised_user/child_accounts/child_account_feedback_reporter_android.cc',
+      'browser/supervised_user/child_accounts/child_account_feedback_reporter_android.h',
+      'browser/supervised_user/child_accounts/child_account_service_android.cc',
+      'browser/supervised_user/child_accounts/child_account_service_android.h',
+    ],
     # TODO(bauerb): This code should be removed (on desktop) once child account
     # support has launched (https://crbug.com/505443).
     'chrome_browser_supervised_user_legacy_sources': [
@@ -2897,14 +2916,6 @@
       'browser/sync/glue/extensions_activity_monitor.h',
       'browser/sync/glue/sync_start_util.cc',
       'browser/sync/glue/sync_start_util.h',
-      'browser/sync/glue/synced_tab_delegate_android.cc',
-      'browser/sync/glue/synced_tab_delegate_android.h',
-      'browser/sync/glue/synced_window_delegate_android.cc',
-      'browser/sync/glue/synced_window_delegate_android.h',
-      'browser/sync/glue/synced_window_delegates_getter_android.cc',
-      'browser/sync/glue/synced_window_delegates_getter_android.h',
-      'browser/sync/profile_sync_service_android.cc',
-      'browser/sync/profile_sync_service_android.h',
       'browser/sync/profile_sync_service_factory.cc',
       'browser/sync/profile_sync_service_factory.h',
       'browser/sync/sessions/notification_service_sessions_router.cc',
@@ -2914,6 +2925,17 @@
       'browser/sync/sync_startup_tracker.cc',
       'browser/sync/sync_startup_tracker.h',
     ],
+    # Sync sources used when android_java_ui is enabled.
+    'chrome_browser_sync_android_java_ui_sources': [
+      'browser/sync/glue/synced_tab_delegate_android.cc',
+      'browser/sync/glue/synced_tab_delegate_android.h',
+      'browser/sync/glue/synced_window_delegate_android.cc',
+      'browser/sync/glue/synced_window_delegate_android.h',
+      'browser/sync/profile_sync_service_android.cc',
+      'browser/sync/profile_sync_service_android.h',
+      'browser/sync/glue/synced_window_delegates_getter_android.cc',
+      'browser/sync/glue/synced_window_delegates_getter_android.h',
+    ],
     'chrome_browser_task_manager_sources': [
       # Stats collection for CAPS (uses old task manager):
       'browser/caps/generate_state_json.cc',
@@ -3606,13 +3628,13 @@
         ['notifications==1', {
           'sources': [ '<@(chrome_browser_notifications_sources)' ],
           'conditions': [
-            ['OS!="android"', {
+            ['android_java_ui==0', {
               'sources': [
                 '<@(chrome_browser_notifications_non_android_sources)',
               ],
             }, {
               'sources': [
-                '<@(chrome_browser_notifications_android_sources)',
+                '<@(chrome_browser_notifications_android_java_ui_sources)',
               ],
             }],
           ],
@@ -3665,21 +3687,9 @@
           'dependencies': [
             '../build/android/ndk.gyp:cpu_features',
             '../components/components.gyp:cdm_browser',
-            '../components/components.gyp:data_reduction_proxy_content',
-            '../components/components.gyp:data_usage_android',
-            '../components/components.gyp:enhanced_bookmarks',
-            '../components/components.gyp:offline_pages',
-            '../components/components.gyp:precache_content',
-            '../components/components.gyp:precache_core',
-            '../components/components.gyp:service_tab_launcher',
-            '../components/components.gyp:toolbar',
-            '../components/components.gyp:web_contents_delegate_android',
             '../components/components_resources.gyp:components_resources',
             '../third_party/android_opengl/etc1/etc1.gyp:etc1',
             '../third_party/libaddressinput/libaddressinput.gyp:libaddressinput_util',
-            'chrome_browser_jni_headers',
-            'client_discourse_context_proto',
-            'delta_file_proto',
           ],
           'dependencies!': [
             '../components/components.gyp:storage_monitor',
@@ -3688,10 +3698,35 @@
           ],
           'sources': [
             '<@(chrome_browser_android_sources)',
-            '<@(chrome_browser_bookmark_android_sources)',
            ],
-          'defines': [ 'ENABLE_DATA_REDUCTION_PROXY_DEBUGGING' ],
           'conditions': [
+            ['android_java_ui==1', {
+              'dependencies': [
+                '../components/components.gyp:data_reduction_proxy_content',
+                '../components/components.gyp:data_usage_android',
+                '../components/components.gyp:enhanced_bookmarks',
+                '../components/components.gyp:offline_pages',
+                '../components/components.gyp:precache_content',
+                '../components/components.gyp:precache_core',
+                '../components/components.gyp:service_tab_launcher',
+                '../components/components.gyp:toolbar',
+                '../components/components.gyp:web_contents_delegate_android',
+                'chrome_browser_jni_headers',
+                'client_discourse_context_proto',
+                'delta_file_proto',
+              ],
+              'sources': [
+                '<@(chrome_browser_android_java_ui_sources)',
+                '<@(chrome_browser_bookmark_android_sources)',
+                '<@(chrome_browser_sync_android_java_ui_sources)',
+                '<@(chrome_browser_supervised_user_android_java_ui_sources)',
+                '<@(chrome_browser_ssl_android_java_ui_sources)',
+                '<@(chrome_browser_search_engines_android_java_ui_sources)',
+                '<@(chrome_browser_permissions_android_java_ui_sources)',
+                '<@(chrome_browser_history_android_java_ui_sources)',
+               ],
+              'defines': [ 'ENABLE_DATA_REDUCTION_PROXY_DEBUGGING' ],
+            }],
             ['use_seccomp_bpf==1', {
               'defines': ['USE_SECCOMP_BPF'],
               'dependencies': [
@@ -3939,7 +3974,7 @@
     },
   ],
   'conditions': [
-    ['OS=="android"', {
+    ['android_java_ui == 1', {
       'targets': [
         {
           # GN: //chrome/browser:jni_headers
diff --git a/chrome/chrome_browser_ui.gypi b/chrome/chrome_browser_ui.gypi
index 816ddb3..c3d58c9 100644
--- a/chrome/chrome_browser_ui.gypi
+++ b/chrome/chrome_browser_ui.gypi
@@ -15,8 +15,6 @@
       'browser/ui/android/android_about_app_info.h',
       'browser/ui/android/external_protocol_dialog_android.cc',
       'browser/ui/android/status_tray_android.cc',
-      'browser/ui/android/tab_model/tab_model_list.cc',
-      'browser/ui/android/tab_model/tab_model_list.h',
       'browser/ui/app_list/app_list_util.cc',
       'browser/ui/app_list/app_list_util.h',
       # All other browser/ui/app_list files go in chrome_browser_ui_app_list_sources.
@@ -425,7 +423,7 @@
       'browser/ui/zoom/chrome_zoom_level_prefs.cc',
       'browser/ui/zoom/chrome_zoom_level_prefs.h',
     ],
-    'chrome_browser_ui_android_non_aura_sources': [
+    'chrome_browser_ui_android_java_ui_sources': [
       'browser/ui/android/autofill/autofill_dialog_controller_android.cc',
       'browser/ui/android/autofill/autofill_dialog_controller_android.h',
       'browser/ui/android/autofill/autofill_dialog_result.cc',
@@ -494,6 +492,10 @@
       'browser/ui/android/tab_model/tab_model.h',
       'browser/ui/android/tab_model/tab_model_jni_bridge.cc',
       'browser/ui/android/tab_model/tab_model_jni_bridge.h',
+      'browser/ui/android/tab_model/tab_model_list.cc',
+      'browser/ui/android/tab_model/tab_model_list.h',
+      'browser/ui/android/toolbar/toolbar_model_android.cc',
+      'browser/ui/android/toolbar/toolbar_model_android.h',
       'browser/ui/android/website_settings_popup_android.cc',
       'browser/ui/android/website_settings_popup_android.h',
       'browser/ui/android/window_android_helper.cc',
@@ -720,6 +722,19 @@
       'browser/ui/views/select_file_dialog_extension_factory.cc',
       'browser/ui/views/select_file_dialog_extension_factory.h',
     ],
+    # ARC-only sources.
+    'chrome_browser_ui_chromeos_arc_sources': [
+      'browser/ui/app_list/arc/arc_app_icon.cc',
+      'browser/ui/app_list/arc/arc_app_icon.h',
+      'browser/ui/app_list/arc/arc_app_item.cc',
+      'browser/ui/app_list/arc/arc_app_item.h',
+      'browser/ui/app_list/arc/arc_app_list_prefs_factory.cc',
+      'browser/ui/app_list/arc/arc_app_list_prefs_factory.h',
+      'browser/ui/app_list/arc/arc_app_list_prefs.cc',
+      'browser/ui/app_list/arc/arc_app_list_prefs.h',
+      'browser/ui/app_list/arc/arc_app_model_builder.cc',
+      'browser/ui/app_list/arc/arc_app_model_builder.h',
+    ],
     # ChromeOS sources that should not be included in the official build.
     'chrome_browser_ui_chromeos_non_official_sources': [
       'browser/ui/webui/chromeos/emulator/device_emulator_message_handler.cc',
@@ -2541,6 +2556,8 @@
       'browser/ui/app_list/app_list_controller_delegate_impl.h',
       'browser/ui/app_list/app_list_icon_win.cc',
       'browser/ui/app_list/app_list_icon_win.h',
+      'browser/ui/app_list/app_list_model_builder.cc',
+      'browser/ui/app_list/app_list_model_builder.h',
       'browser/ui/app_list/app_list_positioner.cc',
       'browser/ui/app_list/app_list_positioner.h',
       'browser/ui/app_list/app_list_prefs.cc',
@@ -2770,8 +2787,6 @@
       'browser/ui/webui/local_discovery/local_discovery_ui_handler.h',
     ],
     'chrome_browser_ui_toolbar_model_sources': [
-      'browser/ui/android/toolbar/toolbar_model_android.cc',
-      'browser/ui/android/toolbar/toolbar_model_android.h',
       'browser/ui/toolbar/chrome_toolbar_model.cc',
       'browser/ui/toolbar/chrome_toolbar_model.h',
       'browser/ui/toolbar/toolbar_model_delegate.h',
@@ -2807,6 +2822,7 @@
         'chrome_resources.gyp:platform_locale_settings',
         'chrome_resources.gyp:theme_resources',
         'common',
+        '../base/base.gyp:base_debugging_flags',
         '../components/components.gyp:auto_login_parser',
         '../components/components.gyp:certificate_reporting',
         '../components/components.gyp:device_event_log_component',
@@ -2957,6 +2973,9 @@
             '../ui/chromeos/ui_chromeos.gyp:ui_chromeos_resources',
           ],
         }],
+        ['enable_app_list==1 and chromeos==1', {
+          'sources': [ '<@(chrome_browser_ui_chromeos_arc_sources)' ],
+        }],
         ['use_cups==1', {
           'dependencies': [
             '../printing/printing.gyp:cups',
@@ -3060,15 +3079,21 @@
         }],
         ['OS=="android"', {
           'dependencies': [
-            '../components/components.gyp:web_contents_delegate_android',
             '../third_party/boringssl/boringssl.gyp:boringssl',
-            'chrome_browser_jni_headers',
           ],
-          'dependencies!': [
-             '../ui/events/events.gyp:events',
-             'chrome_browser_ui_views.gyp:browser_ui_views',
+          'conditions': [
+            ['android_java_ui == 1', {
+              'sources': [ '<@(chrome_browser_ui_android_java_ui_sources)' ],
+              'dependencies': [
+                '../components/components.gyp:web_contents_delegate_android',
+                'chrome_browser_jni_headers',
+              ],
+              'dependencies!': [
+                '../ui/events/events.gyp:events',
+                'chrome_browser_ui_views.gyp:browser_ui_views',
+              ],
+            }]
           ],
-          'sources': [ '<@(chrome_browser_ui_android_non_aura_sources)' ],
         }],
         ['OS=="mac"', {
           'sources': [ '<@(chrome_browser_ui_mac_sources)' ],
diff --git a/chrome/chrome_dll.gypi b/chrome/chrome_dll.gypi
index 52a7401a..c873e52 100644
--- a/chrome/chrome_dll.gypi
+++ b/chrome/chrome_dll.gypi
@@ -123,9 +123,7 @@
           ],
           'dependencies': [
             '<@(chromium_browser_dependencies)',
-            '../components/components.gyp:crash_component',
             '../content/content.gyp:content_app_browser',
-            '../third_party/crashpad/crashpad/handler/handler.gyp:crashpad_handler',
           ],
           'conditions': [
             ['OS=="win"', {
@@ -165,8 +163,6 @@
               ],
               'sources': [
                 'app/chrome_dll.rc',
-                'app/chrome_crash_reporter_client.cc',
-                'app/chrome_crash_reporter_client.h',
 
                 # ETW Manifest.
                 '<(SHARED_INTERMEDIATE_DIR)/base/trace_event/etw_manifest/chrome_events_win.rc',
@@ -304,6 +300,7 @@
               'dependencies': [
                 '../components/components.gyp:crash_component',
                 '../components/components.gyp:policy',
+                '../third_party/crashpad/crashpad/handler/handler.gyp:crashpad_handler',
               ],
               'sources': [
                 'app/chrome_crash_reporter_client.cc',
@@ -355,7 +352,6 @@
           'dependencies': [
             '<@(chromium_child_dependencies)',
             '../components/components.gyp:browser_watcher_client',
-            '../components/components.gyp:crash_component',
             '../content/content.gyp:content_app_child',
             'chrome_version_resources',
             'policy_path_parser',
@@ -365,8 +361,6 @@
           ],
           'sources': [
             '<(SHARED_INTERMEDIATE_DIR)/chrome_version/chrome_dll_version.rc',
-            'app/chrome_crash_reporter_client.cc',
-            'app/chrome_crash_reporter_client.h',
             'app/chrome_main.cc',
             'app/chrome_main_delegate.cc',
             'app/chrome_main_delegate.h',
diff --git a/chrome/chrome_exe.gypi b/chrome/chrome_exe.gypi
index 45274699..9117c87e6 100644
--- a/chrome/chrome_exe.gypi
+++ b/chrome/chrome_exe.gypi
@@ -71,10 +71,10 @@
         'app/chrome_watcher_client_win.h',
         'app/chrome_watcher_command_line_win.cc',
         'app/chrome_watcher_command_line_win.h',
-        'app/main_dll_loader_win.cc',
-        'app/main_dll_loader_win.h',
         'app/kasko_client.cc',
         'app/kasko_client.h',
+        'app/main_dll_loader_win.cc',
+        'app/main_dll_loader_win.h',
         'app/signature_validator_win.cc',
         'app/signature_validator_win.h',
       ],
@@ -105,8 +105,13 @@
             'chrome_watcher',
             'chrome_watcher_client',
             '../components/components.gyp:browser_watcher_client',
+            '../components/components.gyp:crash_component',
             '../third_party/crashpad/crashpad/handler/handler.gyp:crashpad_handler_lib',
           ],
+          'sources': [
+            'app/chrome_crash_reporter_client.cc',
+            'app/chrome_crash_reporter_client.h',
+          ],
           'conditions': [
             ['kasko==1', {
               'dependencies': [
diff --git a/chrome/chrome_features.gyp b/chrome/chrome_features.gyp
index 0d29f18..6ff5d76 100644
--- a/chrome/chrome_features.gyp
+++ b/chrome/chrome_features.gyp
@@ -15,6 +15,7 @@
         'buildflag_header_path': 'chrome/common/features.h',
         'buildflag_flags': [
           'ENABLE_GOOGLE_NOW=<(enable_google_now)',
+          'ANDROID_JAVA_UI=<(android_java_ui)',
         ],
       },
     },
diff --git a/chrome/chrome_features.gypi b/chrome/chrome_features.gypi
index a4d8756..06488b1e 100644
--- a/chrome/chrome_features.gypi
+++ b/chrome/chrome_features.gypi
@@ -10,6 +10,11 @@
     'variables': {
       # Conditional variables.
       'conditions': [
+        ['OS=="android"', {
+          'android_java_ui%': 1,
+        }, {
+          'android_java_ui': 0,
+        }],
         ['OS=="android" or OS=="ios"', {
           'enable_google_now%': 0,
         }, {
@@ -21,6 +26,7 @@
     # Anything in the conditions needs to be copied to the outer scope to be
     # accessible.
     'enable_google_now%': '<(enable_google_now)',
+    'android_java_ui%': '<(android_java_ui)',
 
     # Grit defines based on the feature flags. These must be manually added to
     # grit targets.
diff --git a/chrome/chrome_tests_unit.gypi b/chrome/chrome_tests_unit.gypi
index 6ab5482..f569558 100644
--- a/chrome/chrome_tests_unit.gypi
+++ b/chrome/chrome_tests_unit.gypi
@@ -468,6 +468,7 @@
       'browser/ui/webui/browsing_history_handler_unittest.cc',
       'browser/ui/webui/fileicon_source_unittest.cc',
       'browser/ui/webui/log_web_ui_url_unittest.cc',
+      'browser/ui/startup/startup_browser_creator_win_unittest.cc',
       'browser/update_client/chrome_update_query_params_delegate_unittest.cc',
       'common/chrome_content_client_unittest.cc',
       'common/chrome_paths_unittest.cc',
@@ -1591,6 +1592,7 @@
       'browser/ui/webui/options/language_options_handler_unittest.cc',
       'browser/ui/webui/options/pepper_flash_content_settings_utils_unittest.cc',
       'browser/ui/webui/options/sync_setup_handler_unittest.cc',
+      'browser/ui/webui/settings/reset_settings_handler_unittest.cc',
       'browser/ui/webui/settings/sync_handler_unittest.cc',
       'browser/ui/webui/signin/login_ui_service_unittest.cc',
       'browser/ui/webui/sync_internals_message_handler_unittest.cc',
@@ -1646,6 +1648,10 @@
     'chrome_unit_tests_app_list_chromeos_sources': [
       'browser/ui/app_list/search/launcher_search/launcher_search_icon_image_loader_unittest.cc',
     ],
+    # ARC only sources of app_list.
+    'chrome_unit_tests_app_list_chromeos_arc_sources': [
+      'browser/ui/app_list/arc/arc_app_unittest.cc',
+    ],
     # Sources for Offline pages. For now only for Android.
     'chrome_unit_tests_offline_pages_sources': [
       'browser/android/offline_pages/offline_page_mhtml_archiver_unittest.cc',
@@ -2069,6 +2075,7 @@
           ],
           'dependencies': [
             '../components/components.gyp:crash_component',
+            '../third_party/crashpad/crashpad/handler/handler.gyp:crashpad_handler',
             '../win8/win8.gyp:test_registrar_constants',
             '../win8/win8.gyp:test_support_win8',
           ],
@@ -2764,6 +2771,12 @@
         ['enable_app_list==1 and chromeos==1', {
           'sources': [ '<@(chrome_unit_tests_app_list_chromeos_sources)' ],
         }],
+        ['enable_app_list==1 and chromeos==1', {
+          'sources': [ '<@(chrome_unit_tests_app_list_chromeos_arc_sources)' ],
+          'dependencies': [
+            '../components/components.gyp:arc_test_support',
+          ],
+        }],
         ['enable_plugin_installation==0', {
           'sources!': [
             'browser/plugins/plugin_installer_unittest.cc',
diff --git a/chrome/common/BUILD.gn b/chrome/common/BUILD.gn
index 863cedd..1912a22 100644
--- a/chrome/common/BUILD.gn
+++ b/chrome/common/BUILD.gn
@@ -40,7 +40,10 @@
 
 buildflag_header("features") {
   header = "features.h"
-  flags = [ "ENABLE_GOOGLE_NOW=$enable_google_now" ]
+  flags = [
+    "ENABLE_GOOGLE_NOW=$enable_google_now",
+    "ANDROID_JAVA_UI=$android_java_ui",
+  ]
 }
 
 # GYP version: chrome/chrome_common.gypi:common
diff --git a/chrome/common/chrome_paths.cc b/chrome/common/chrome_paths.cc
index 66c7bf2a..4c19077 100644
--- a/chrome/common/chrome_paths.cc
+++ b/chrome/common/chrome_paths.cc
@@ -207,6 +207,8 @@
       // directory.  This avoids the problem of having to re-initialize the
       // exception handler after parsing command line options, which may
       // override the location of the app's profile directory.
+      // TODO(scottmg): Consider supporting --user-data-dir. See
+      // https://crbug.com/565446.
       if (!GetDefaultUserDataDirectory(&cur))
         return false;
 #endif
diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc
index 9443ec0..f71178a 100644
--- a/chrome/common/chrome_switches.cc
+++ b/chrome/common/chrome_switches.cc
@@ -520,6 +520,12 @@
 const char kDisableSimplifiedFullscreenUI[] =
     "disable-simplified-fullscreen-ui";
 
+// Enable the Site Engagement App Banner which triggers app install banners
+// using the site engagement service rather than a navigation-based heuristic.
+// Implicitly enables the site engagement service.
+const char kEnableSiteEngagementAppBanner[] =
+    "enable-site-engagement-app-banner";
+
 // Enable the Site Engagement Eviction Policy which evicts temporary storage
 // using the site engagement service. Implicitly enables the site engagement
 // service.
diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h
index 6a4e48f..67908f2 100644
--- a/chrome/common/chrome_switches.h
+++ b/chrome/common/chrome_switches.h
@@ -150,6 +150,7 @@
 extern const char kDisableSettingsWindow[];
 extern const char kEnableSimplifiedFullscreenUI[];
 extern const char kDisableSimplifiedFullscreenUI[];
+extern const char kEnableSiteEngagementAppBanner[];
 extern const char kEnableSiteEngagementEvictionPolicy[];
 extern const char kEnableSiteEngagementService[];
 extern const char kEnableSupervisedUserManagedBookmarksFolder[];
diff --git a/chrome/common/extensions/api/extension_action/action_info.cc b/chrome/common/extensions/api/extension_action/action_info.cc
index 8cf0386..a3be61b 100644
--- a/chrome/common/extensions/api/extension_action/action_info.cc
+++ b/chrome/common/extensions/api/extension_action/action_info.cc
@@ -91,25 +91,17 @@
     const base::DictionaryValue* icons_value = NULL;
     std::string default_icon;
     if (dict->GetDictionary(keys::kPageActionDefaultIcon, &icons_value)) {
-      int icon_sizes[extension_misc::kNumExtensionActionIconSizes];
-      for (size_t i = 0u; i < extension_misc::kNumExtensionActionIconSizes; ++i)
-        icon_sizes[i] = extension_misc::kExtensionActionIconSizes[i].size;
-      if (!manifest_handler_helpers::LoadIconsFromDictionary(
-              icons_value,
-              icon_sizes,
-              extension_misc::kNumExtensionActionIconSizes,
-              &result->default_icon,
-              error)) {
+      if (!manifest_handler_helpers::LoadAllIconsFromDictionary(
+              icons_value, &result->default_icon, error)) {
         return scoped_ptr<ActionInfo>();
       }
     } else if (dict->GetString(keys::kPageActionDefaultIcon, &default_icon) &&
                manifest_handler_helpers::NormalizeAndValidatePath(
                    &default_icon)) {
-      // Choose the most optimistic (highest) icon density - e.g. 38 not 19 -
-      // regardless of the actual icon resolution, whatever that happens to be.
-      // Code elsewhere knows how to scale 38 down to 19.
-      result->default_icon.Add(extension_misc::EXTENSION_ICON_ACTION *
-                                   extension_misc::kNumExtensionActionIconSizes,
+      // Choose the most optimistic (highest) icon density regardless of the
+      // actual icon resolution, whatever that happens to be. Code elsewhere
+      // knows how to scale down to 19.
+      result->default_icon.Add(extension_misc::EXTENSION_ICON_GIGANTOR,
                                default_icon);
     } else {
       *error = base::ASCIIToUTF16(errors::kInvalidPageActionIconPath);
diff --git a/chrome/common/extensions/api/extension_action/browser_action_manifest_unittest.cc b/chrome/common/extensions/api/extension_action/browser_action_manifest_unittest.cc
index 4693a94..539477b6 100644
--- a/chrome/common/extensions/api/extension_action/browser_action_manifest_unittest.cc
+++ b/chrome/common/extensions/api/extension_action/browser_action_manifest_unittest.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/common/extensions/api/extension_action/action_info.h"
 #include "chrome/common/extensions/manifest_tests/chrome_manifest_test.h"
+#include "extensions/common/constants.h"
 #include "extensions/common/error_utils.h"
 #include "extensions/common/extension_builder.h"
 #include "extensions/common/extension_icon_set.h"
@@ -60,23 +61,27 @@
   const ExtensionIconSet& icons = browser_action_info->default_icon;
 
   EXPECT_EQ(1u, icons.map().size());
-  EXPECT_EQ("icon.png", icons.Get(38, ExtensionIconSet::MATCH_EXACTLY));
+  EXPECT_EQ("icon.png", icons.Get(extension_misc::EXTENSION_ICON_GIGANTOR,
+                                  ExtensionIconSet::MATCH_EXACTLY));
 }
 
 TEST_F(BrowserActionManifestTest,
        BrowserActionManifestIcons_DictDefaultIcon) {
+  // Arbitrary sizes should be allowed (useful for various scale factors).
   scoped_refptr<const Extension> extension =
       ExtensionBuilder()
-      .SetManifest(DictionaryBuilder()
-                   .Set("name", "Dictionary default icon")
-                   .Set("version", "1.0.0")
-                   .Set("manifest_version", 2)
-                   .Set("browser_action", DictionaryBuilder()
-                       .Set("default_icon", DictionaryBuilder()
-                           .Set("19", "icon19.png")
-                           .Set("24", "icon24.png")  // Should be ignored.
-                           .Set("38", "icon38.png"))))
-      .Build();
+          .SetManifest(
+              DictionaryBuilder()
+                  .Set("name", "Dictionary default icon")
+                  .Set("version", "1.0.0")
+                  .Set("manifest_version", 2)
+                  .Set("browser_action",
+                       DictionaryBuilder().Set("default_icon",
+                                               DictionaryBuilder()
+                                                   .Set("19", "icon19.png")
+                                                   .Set("24", "icon24.png")
+                                                   .Set("38", "icon38.png"))))
+          .Build();
 
   ASSERT_TRUE(extension.get());
   const ActionInfo* browser_action_info =
@@ -86,9 +91,10 @@
 
   const ExtensionIconSet& icons = browser_action_info->default_icon;
 
-  // 24px icon should be ignored.
-  EXPECT_EQ(2u, icons.map().size());
+  // 24px icon should be included.
+  EXPECT_EQ(3u, icons.map().size());
   EXPECT_EQ("icon19.png", icons.Get(19, ExtensionIconSet::MATCH_EXACTLY));
+  EXPECT_EQ("icon24.png", icons.Get(24, ExtensionIconSet::MATCH_EXACTLY));
   EXPECT_EQ("icon38.png", icons.Get(38, ExtensionIconSet::MATCH_EXACTLY));
 }
 
diff --git a/chrome/common/extensions/docs/examples/api/desktopCapture/app.js b/chrome/common/extensions/docs/examples/api/desktopCapture/app.js
index 6445baf..65823af 100644
--- a/chrome/common/extensions/docs/examples/api/desktopCapture/app.js
+++ b/chrome/common/extensions/docs/examples/api/desktopCapture/app.js
@@ -2,50 +2,121 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-function gotStream(stream) {
-  console.log("Received local stream");
-  var video = document.querySelector("video");
-  video.src = URL.createObjectURL(stream);
-  localstream = stream;
-  stream.onended = function() { console.log("Ended"); };
-}
+'use strict';
 
-function getUserMediaError() {
-  console.log("getUserMedia() failed.");
-}
-
-function onAccessApproved(id) {
-  if (!id) {
-    console.log("Access rejected.");
-    return;
-  }
-
-  navigator.webkitGetUserMedia({
-    audio:false,
-    video: {
-      mandatory: {
-        chromeMediaSource: "desktop",
-        chromeMediaSourceId: id,
-        maxWidth:screen.width,
-        maxHeight:screen.height} }
-  }, gotStream, getUserMediaError);
-}
+const DESKTOP_MEDIA = ['screen', 'window'];
 
 var pending_request_id = null;
+var pc1 = null;
+var pc2 = null;
 
-document.querySelector('#start').addEventListener('click', function(e) {
+// Launch the chooseDesktopMedia().
+document.querySelector('#start').addEventListener('click', function(event) {
   pending_request_id = chrome.desktopCapture.chooseDesktopMedia(
-      ["screen", "window"], onAccessApproved);
+      DESKTOP_MEDIA, onAccessApproved);
 });
 
-document.querySelector('#cancel').addEventListener('click', function(e) {
+document.querySelector('#cancel').addEventListener('click', function(event) {
   if (pending_request_id != null) {
     chrome.desktopCapture.cancelChooseDesktopMedia(pending_request_id);
   }
 });
 
 document.querySelector('#startFromBackgroundPage')
-    .addEventListener('click', function(e) {
+    .addEventListener('click', function(event) {
       chrome.runtime.sendMessage(
           {}, function(response) { console.log(response.farewell); });
     });
+
+// Launch webkitGetUserMedia() based on selected media id.
+function onAccessApproved(id) {
+  if (!id) {
+    console.log('Access rejected.');
+    return;
+  }
+
+  navigator.webkitGetUserMedia({
+    audio:{
+      mandatory: {
+        chromeMediaSource: 'desktop',
+        chromeMediaSourceId: id} },
+    video: {
+      mandatory: {
+        chromeMediaSource: 'desktop',
+        chromeMediaSourceId: id,
+        maxWidth:screen.width,
+        maxHeight:screen.height} }
+  }, gotStream, getUserMediaError);
+}
+
+function getUserMediaError(error) {
+  console.log('navigator.webkitGetUserMedia() errot: ', error);
+}
+
+// Capture video/audio of media and initialize RTC communication.
+function gotStream(stream) {
+  console.log('Received local stream', stream);
+  var video = document.querySelector('video');
+  video.src = URL.createObjectURL(stream);
+  stream.onended = function() { console.log('Ended'); };
+
+  var servers = null;
+  pc1 = new webkitRTCPeerConnection(servers);
+  pc1.onicecandidate = function(event) {
+    onIceCandidate(pc1, event);
+  };
+  pc2 = new webkitRTCPeerConnection(servers);
+  pc2.onicecandidate = function(event) {
+    onIceCandidate(pc2, event);
+  };
+  pc1.oniceconnectionstatechange = function(event) {
+    onIceStateChange(pc1, event);
+  };
+  pc2.oniceconnectionstatechange = function(event) {
+    onIceStateChange(pc2, event);
+  };
+  pc2.onaddstream = gotRemoteStream;
+
+  pc1.addStream(stream);
+
+  pc1.createOffer(onCreateOfferSuccess);
+}
+
+function onCreateOfferSuccess(desc) {
+  pc1.setLocalDescription(desc);
+  pc2.setRemoteDescription(desc);
+  // Since the 'remote' side has no media stream we need
+  // to pass in the right constraints in order for it to
+  // accept the incoming offer of audio and video.
+  var sdpConstraints = {
+    'mandatory': {
+      'OfferToReceiveAudio': true,
+      'OfferToReceiveVideo': true
+    }
+  };
+  pc2.createAnswer(onCreateAnswerSuccess, function(){}, sdpConstraints);
+}
+
+function gotRemoteStream(event) {
+  // Call the polyfill wrapper to attach the media stream to this element.
+  console.log('hitting this code');
+  remoteVideo.src = URL.createObjectURL(event.stream);
+}
+
+function onCreateAnswerSuccess(desc) {
+  pc2.setLocalDescription(desc);
+  pc1.setRemoteDescription(desc);
+}
+
+function onIceCandidate(pc, event) {
+  if (event.candidate) {
+    var remotePC = (pc === pc1) ? pc2 : pc1;
+    remotePC.addIceCandidate(new RTCIceCandidate(event.candidate));
+  }
+}
+
+function onIceStateChange(pc, event) {
+  if (pc) {
+    console.log('ICE state change event: ', event);
+  }
+}
diff --git a/chrome/common/extensions/docs/examples/api/desktopCapture/background.js b/chrome/common/extensions/docs/examples/api/desktopCapture/background.js
index c1574a53..332b4515 100644
--- a/chrome/common/extensions/docs/examples/api/desktopCapture/background.js
+++ b/chrome/common/extensions/docs/examples/api/desktopCapture/background.js
@@ -5,8 +5,8 @@
 chrome.app.runtime.onLaunched.addListener(function() {
   chrome.app.window.create('index.html', {
     bounds: {
-      width: 700,
-      height: 600
+      width: 1080,
+      height: 420
     }
   });
 });
diff --git a/chrome/common/extensions/docs/examples/api/desktopCapture/index.html b/chrome/common/extensions/docs/examples/api/desktopCapture/index.html
index f8db183..fca9053 100644
--- a/chrome/common/extensions/docs/examples/api/desktopCapture/index.html
+++ b/chrome/common/extensions/docs/examples/api/desktopCapture/index.html
@@ -9,15 +9,18 @@
     -webkit-flex-direction: column;
   }
   video {
-    width: 640px;
-    height: 480px;
+    width: 480px;
+    height: 360px;
     border: 1px solid #e2e2e2;
     box-shadow: 0 1px 1px rgba(0,0,0,0.2);
   }
 </style>
 </head>
 <body>
-  <video id="video" autoplay></video>
+  <div>
+    <video id="video" autoplay></video>
+    <video id="remoteVideo" autoplay></video>
+  </div>
   <p>
     <button id="start">Start</button>
     <button id="cancel">Cancel</button>
diff --git a/chrome/common/features.gni b/chrome/common/features.gni
index 2e92745c..3188c6c 100644
--- a/chrome/common/features.gni
+++ b/chrome/common/features.gni
@@ -7,6 +7,12 @@
 
 declare_args() {
   enable_google_now = !is_ios && !is_android
+
+  # Whether the Java UI is being used (Java infobars and popups, Java native
+  # settings and first run experience, sign-in etc.).
+  # Default to true if compiling for android, but allow this being overriden
+  # through the environment.
+  android_java_ui = is_android
 }
 
 chrome_grit_defines = [ "enable_google_now=$enable_google_now" ]
diff --git a/chrome/common/localized_error.cc b/chrome/common/localized_error.cc
index 4ce95ed..e36cfe1e 100644
--- a/chrome/common/localized_error.cc
+++ b/chrome/common/localized_error.cc
@@ -25,7 +25,6 @@
 #include "components/url_formatter/url_formatter.h"
 #include "net/base/escape.h"
 #include "net/base/net_errors.h"
-#include "third_party/WebKit/public/platform/WebURLError.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/webui/web_ui_util.h"
 
@@ -33,7 +32,6 @@
 #include "base/win/windows_version.h"
 #endif
 
-using blink::WebURLError;
 using error_page::OfflinePageStatus;
 
 // Some error pages have no details.
@@ -774,7 +772,6 @@
       base::string16 button_text =
           l10n_util::GetStringUTF16(IDS_ERRORPAGES_BUTTON_SHOW_OFFLINE_COPY);
       show_offline_copy_button->SetString("msg", button_text);
-      show_offline_copy_button->SetString("title", button_text);
       error_strings->Set("showOfflineCopyButton", show_offline_copy_button);
     } else if (offline_page_status ==
                OfflinePageStatus::HAS_OTHER_OFFLINE_PAGES) {
@@ -783,7 +780,6 @@
       base::string16 button_text =
           l10n_util::GetStringUTF16(IDS_ERRORPAGES_BUTTON_SHOW_OFFLINE_PAGES);
       show_offline_pages_button->SetString("msg", button_text);
-      show_offline_pages_button->SetString("title", button_text);
       error_strings->Set("showOfflinePagesButton", show_offline_pages_button);
     }
   }
@@ -925,10 +921,11 @@
   }
 }
 
-base::string16 LocalizedError::GetErrorDetails(const blink::WebURLError& error,
+base::string16 LocalizedError::GetErrorDetails(const std::string& error_domain,
+                                               int error_code,
                                                bool is_post) {
   const LocalizedErrorMap* error_map =
-      LookupErrorMap(error.domain.utf8(), error.reason, is_post);
+      LookupErrorMap(error_domain, error_code, is_post);
   if (error_map)
     return l10n_util::GetStringUTF16(error_map->details_resource_id);
   else
diff --git a/chrome/common/localized_error.h b/chrome/common/localized_error.h
index ed7ceb5..ed6009f 100644
--- a/chrome/common/localized_error.h
+++ b/chrome/common/localized_error.h
@@ -17,10 +17,6 @@
 class DictionaryValue;
 }
 
-namespace blink {
-struct WebURLError;
-}
-
 namespace error_page {
 struct ErrorPageParams;
 }
@@ -42,7 +38,8 @@
                          base::DictionaryValue* strings);
 
   // Returns a description of the encountered error.
-  static base::string16 GetErrorDetails(const blink::WebURLError& error,
+  static base::string16 GetErrorDetails(const std::string& error_domain,
+                                        int error_code,
                                         bool is_post);
 
   // Returns true if an error page exists for the specified parameters.
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc
index 79f0662..dd363714 100644
--- a/chrome/common/pref_names.cc
+++ b/chrome/common/pref_names.cc
@@ -5,7 +5,6 @@
 #include "chrome/common/pref_names.h"
 
 #include "base/basictypes.h"
-#include "chrome/common/features.h"
 #include "chrome/common/pref_font_webkit_names.h"
 
 namespace prefs {
@@ -13,6 +12,10 @@
 // *************** PROFILE PREFS ***************
 // These are attached to the user profile
 
+#if defined(OS_CHROMEOS) && defined(ENABLE_APP_LIST)
+// A preference to keep list of ARC apps and its state.
+const char kArcApps[] = "arc.apps";
+#endif
 
 // A bool pref that keeps whether the child status for this profile was already
 // successfully checked via ChildAccountService.
@@ -367,7 +370,7 @@
 // Boolean that is true when Suggest support is enabled.
 const char kSearchSuggestEnabled[] = "search.suggest_enabled";
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
 // String indicating the Contextual Search enabled state.
 // "false" - opt-out (disabled)
 // "" (empty string) - undecided
@@ -991,7 +994,7 @@
 const char kAutofillGeneratedCardBubbleTimesShown[] =
     "autofill.generated_card_bubble_times_shown";
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
 // A dictionary that tracks the defaults to be set on the next invocation
 // of the requestAutocomplete dialog.
 const char kAutofillDialogDefaults[] = "autofill.rac_dialog_defaults";
@@ -1256,7 +1259,7 @@
 const char kStabilitySystemUncleanShutdownCount[] =
     "user_experience_metrics.stability.system_unclean_shutdowns";
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
 // Activity type that is currently in the foreground for the UMA session.
 // Uses the ActivityTypeIds::Type enum.
 const char kStabilityForegroundActivityType[] =
@@ -1416,7 +1419,7 @@
 // Customized app page names that appear on the New Tab Page.
 const char kNtpAppPageNames[] = "ntp.app_page_names";
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
 // Keeps track of currently open tabs collapsed state in the Other Devices menu.
 const char kNtpCollapsedCurrentlyOpenTabs[] = "ntp.collapsed_open_tabs";
 #endif
@@ -1424,7 +1427,7 @@
 // Keeps track of which sessions are collapsed in the Other Devices menu.
 const char kNtpCollapsedForeignSessions[] = "ntp.collapsed_foreign_sessions";
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
 // Keeps track of recently closed tabs collapsed state in the Other Devices
 // menu.
 const char kNtpCollapsedRecentlyClosedTabs[] =
@@ -1440,7 +1443,7 @@
 // Which page should be visible on the new tab page v4
 const char kNtpShownPage[] = "ntp.shown_page";
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
 // Ordered list of website suggestions shown on the new tab page that will allow
 // retaining the order even if the suggestions change over time.
 const char kNTPSuggestionsURL[] = "ntp.suggestions_url";
@@ -1542,7 +1545,7 @@
 // corresponding access token.
 const char kGeolocationAccessToken[] = "geolocation.access_token";
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
 // Boolean that controls the enabled-state of Geolocation in content.
 const char kGeolocationEnabled[] = "geolocation.enabled";
 #endif
@@ -2113,7 +2116,7 @@
 const char kWatchdogExtensionActive[] =
     "profile.extensions.activity_log.num_consumers_active";
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
 // A list of partner bookmark rename/remove mappings.
 // Each list item is a dictionary containing a "url", a "provider_title" and
 // "mapped_title" entries, detailing the bookmark target URL (if any), the title
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h
index 7563ff6..1ead3de 100644
--- a/chrome/common/pref_names.h
+++ b/chrome/common/pref_names.h
@@ -15,6 +15,9 @@
 namespace prefs {
 
 // Profile prefs. Please add Local State prefs below instead.
+#if defined(OS_CHROMEOS) && defined(ENABLE_APP_LIST)
+extern const char kArcApps[];
+#endif
 extern const char kChildAccountStatusKnown[];
 extern const char kDefaultApps[];
 extern const char kDisableScreenshots[];
@@ -146,7 +149,7 @@
 extern const char kSSLErrorOverrideAllowed[];
 extern const char kIncognitoModeAvailability[];
 extern const char kSearchSuggestEnabled[];
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
 extern const char kContextualSearchEnabled[];
 #endif
 #if defined(OS_MACOSX)
@@ -332,7 +335,7 @@
 extern const char kAutofillDialogSaveData[];
 extern const char kAutofillDialogWalletShippingSameAsBilling[];
 extern const char kAutofillGeneratedCardBubbleTimesShown[];
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
 extern const char kAutofillDialogDefaults[];
 #endif
 
@@ -415,7 +418,7 @@
 // Android has it's own metric / crash reporting implemented in Android
 // Java code so kMetricsReportingEnabled doesn't make sense. We use this
 // to inform crashes_ui that we have enabled crash reporting.
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
 extern const char kCrashReportingEnabled[];
 #endif
 
@@ -430,7 +433,7 @@
 extern const char kStabilityOtherUserCrashCount[];
 extern const char kStabilityKernelCrashCount[];
 extern const char kStabilitySystemUncleanShutdownCount[];
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
 extern const char kStabilityForegroundActivityType[];
 extern const char kStabilityLaunchedActivityFlags[];
 extern const char kStabilityLaunchedActivityCounts[];
@@ -500,17 +503,17 @@
 extern const char kDisablePluginFinder[];
 
 extern const char kNtpAppPageNames[];
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
 extern const char kNtpCollapsedCurrentlyOpenTabs[];
 #endif
 extern const char kNtpCollapsedForeignSessions[];
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
 extern const char kNtpCollapsedRecentlyClosedTabs[];
 extern const char kNtpCollapsedSnapshotDocument[];
 extern const char kNtpCollapsedSyncPromo[];
 #endif
 extern const char kNtpShownPage[];
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
 extern const char kNTPSuggestionsURL[];
 extern const char kNTPSuggestionsIsPersonal[];
 #endif
@@ -551,7 +554,7 @@
 extern const char kWebAppCreateInQuickLaunchBar[];
 
 extern const char kGeolocationAccessToken[];
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
 extern const char kGeolocationEnabled[];
 #endif
 
@@ -766,7 +769,7 @@
 
 extern const char kWatchdogExtensionActive[];
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
 extern const char kPartnerBookmarkMappings[];
 #endif
 
diff --git a/chrome/common/url_constants.cc b/chrome/common/url_constants.cc
index 70a108201..99a662e 100644
--- a/chrome/common/url_constants.cc
+++ b/chrome/common/url_constants.cc
@@ -7,6 +7,7 @@
 #include <algorithm>
 
 #include "base/basictypes.h"
+#include "chrome/common/features.h"
 #include "content/public/common/url_constants.h"
 #include "url/url_util.h"
 
@@ -87,7 +88,7 @@
 const char kChromeUIUserActionsURL[] = "chrome://user-actions/";
 const char kChromeUIVersionURL[] = "chrome://version/";
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
 const char kChromeUIContextualSearchPromoURL[] =
     "chrome://contextual-search-promo";
 const char kChromeUINativeScheme[] = "chrome-native";
diff --git a/chrome/common/url_constants.h b/chrome/common/url_constants.h
index 724b8c5f..7f471c8 100644
--- a/chrome/common/url_constants.h
+++ b/chrome/common/url_constants.h
@@ -11,6 +11,7 @@
 #include <vector>
 
 #include "build/build_config.h"
+#include "chrome/common/features.h"
 #include "content/public/common/url_constants.h"
 
 namespace chrome {
@@ -83,7 +84,7 @@
 extern const char kChromeUIUserActionsURL[];
 extern const char kChromeUIVersionURL[];
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
 extern const char kChromeUIContextualSearchPromoURL[];
 extern const char kChromeUINativeScheme[];
 extern const char kChromeUINativeNewTabURL[];
diff --git a/chrome/ct_dm.isolate b/chrome/ct_dm.isolate
index 0a8c726..ee573c4 100644
--- a/chrome/ct_dm.isolate
+++ b/chrome/ct_dm.isolate
@@ -10,7 +10,7 @@
           '../../skia/resources/',
           '../../skia/out/Debug/dm',
           '../content/test/ct/run_ct_dm.py',
-          '../content/test/ct/slave<(SLAVE_NUM)/skps/',
+          '../../skps/slave<(SLAVE_NUM)/',
         ],
         'command': [
           'python',
diff --git a/chrome/installer/mac/sign_versioned_dir.sh.in b/chrome/installer/mac/sign_versioned_dir.sh.in
index f68b7aa..c47cb954 100644
--- a/chrome/installer/mac/sign_versioned_dir.sh.in
+++ b/chrome/installer/mac/sign_versioned_dir.sh.in
@@ -43,6 +43,8 @@
 framework="${versioned_dir}/@MAC_PRODUCT_NAME@ Framework.framework"
 crashpad_handler="${framework}/Helpers/crashpad_handler"
 helper_app="${versioned_dir}/@MAC_PRODUCT_NAME@ Helper.app"
+app_mode_loader_app="${framework}/Resources/app_mode_loader.app"
+app_mode_loader="${app_mode_loader_app}/Contents/MacOS/app_mode_loader"
 
 requirement_suffix="\
 and certificate leaf = H\"85cee8254216185620ddc8851c7a9fc4dfe120ef\"\
@@ -54,17 +56,38 @@
     "${crashpad_handler}" \
     -r="designated => identifier \"crashpad_handler\" \
 ${requirement_suffix}" --options "${enforcement_flags}"
+
+# The app mode loader bundle is modified dynamically at runtime. Just sign the
+# executable, which shouldn't change. In order to do this, the executable needs
+# to be copied out of the bundle, signed, and then copied back in. The resulting
+# bundle's signature won't validate normally, but if the executable file is
+# verified in isolation or with --ignore-resources, it will. Because the
+# bundle's signature won't validate on its own, don't set any of the enforcement
+# flags.
+app_mode_loader_tmp="$(mktemp -t app_mode_loader)"
+cp "${app_mode_loader}" "${app_mode_loader_tmp}"
+codesign --sign "${codesign_id}" --keychain "${codesign_keychain}" \
+    "${app_mode_loader_tmp}" \
+    -r="designated => identifier \"app_mode_loader\" \
+${requirement_suffix}"
+cp "${app_mode_loader_tmp}" "${app_mode_loader}"
+rm -f "${app_mode_loader_tmp}"
+
 codesign --sign "${codesign_id}" --keychain "${codesign_keychain}" \
     "${framework}" \
     -r="designated => identifier \"com.google.Chrome.framework\" \
 ${requirement_suffix}"
+
 codesign --sign "${codesign_id}" --keychain "${codesign_keychain}" \
     "${helper_app}" \
     -r="designated => identifier \"com.google.Chrome.helper\" \
 ${requirement_suffix}" --options "${enforcement_flags}"
 
 # Verify everything. Don't use --deep on the framework because Keystone's
-# signature is in a transitional state (radar 18474911).
+# signature is in a transitional state (radar 18474911). Don't verify
+# app_mode_loader independently because --ignore-resources is unrecognized
+# before 10.11 (bug 565859).
 codesign --verify --deep "${crashpad_handler}"
+# codesign --verify --ignore-resources "${app_mode_loader}"
 codesign --verify "${framework}"
 codesign --verify --deep "${helper_app}"
diff --git a/chrome/installer/util/l10n_string_util.cc b/chrome/installer/util/l10n_string_util.cc
index 96f2ce7..5d93814 100644
--- a/chrome/installer/util/l10n_string_util.cc
+++ b/chrome/installer/util/l10n_string_util.cc
@@ -7,8 +7,10 @@
 #include "chrome/installer/util/l10n_string_util.h"
 
 #include <atlbase.h>
+#include <stdint.h>
 
 #include <algorithm>
+#include <limits>
 
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
@@ -89,7 +91,7 @@
 
   // The cast is safe because url_path has limited length
   // (see the definition of full_exe_path and resource).
-  DCHECK(kuint32max > (url_path.size() * 3));
+  DCHECK(std::numeric_limits<uint32_t>::max() > (url_path.size() * 3));
   DWORD count = static_cast<DWORD>(url_path.size() * 3);
   scoped_ptr<wchar_t[]> url_canon(new wchar_t[count]);
   HRESULT hr = ::UrlCanonicalizeW(url_path.c_str(), url_canon.get(),
diff --git a/chrome/renderer/autofill/form_autofill_browsertest.cc b/chrome/renderer/autofill/form_autofill_browsertest.cc
index bc7a762..6e876015 100644
--- a/chrome/renderer/autofill/form_autofill_browsertest.cc
+++ b/chrome/renderer/autofill/form_autofill_browsertest.cc
@@ -2068,6 +2068,67 @@
                                         &field));
 }
 
+// Tests that the |should_autocomplete| is set to false for all the fields when
+// an autocomplete='off' attribute is set for the form in HTML.
+TEST_F(FormAutofillTest, WebFormElementToFormData_AutocompleteOff_OnForm) {
+  LoadHTML(
+      "<FORM name='TestForm' id='form' action='http://cnn.com' method='post' "
+      "autocomplete='off'>"
+      "  <LABEL for='firstname'>First name:</LABEL>"
+      "    <INPUT type='text' id='firstname' value='John'/>"
+      "  <LABEL for='lastname'>Last name:</LABEL>"
+      "    <INPUT type='text' id='lastname' value='Smith'/>"
+      "  <LABEL for='street-address'>Address:</LABEL>"
+      "    <INPUT type='text' id='addressline1' value='123 Test st.'/>"
+      "</FORM>");
+
+  WebFrame* frame = GetMainFrame();
+  ASSERT_NE(nullptr, frame);
+
+  WebFormElement web_form =
+      frame->document().getElementById("form").to<WebFormElement>();
+  ASSERT_FALSE(web_form.isNull());
+
+  FormData form;
+  EXPECT_TRUE(WebFormElementToFormData(web_form, WebFormControlElement(),
+                                       EXTRACT_NONE, &form, nullptr));
+
+  for (const FormFieldData& field : form.fields) {
+    EXPECT_FALSE(field.should_autocomplete);
+  }
+}
+
+// Tests that the |should_autocomplete| is set to false only for the field
+// which has an autocomplete='off' attribute set for it in HTML.
+TEST_F(FormAutofillTest, WebFormElementToFormData_AutocompleteOff_OnField) {
+  LoadHTML(
+      "<FORM name='TestForm' id='form' action='http://cnn.com' method='post'>"
+      "  <LABEL for='firstname'>First name:</LABEL>"
+      "    <INPUT type='text' id='firstname' value='John' autocomplete='off'/>"
+      "  <LABEL for='lastname'>Last name:</LABEL>"
+      "    <INPUT type='text' id='lastname' value='Smith'/>"
+      "  <LABEL for='street-address'>Address:</LABEL>"
+      "    <INPUT type='text' id='addressline1' value='123 Test st.'/>"
+      "</FORM>");
+
+  WebFrame* frame = GetMainFrame();
+  ASSERT_NE(nullptr, frame);
+
+  WebFormElement web_form =
+      frame->document().getElementById("form").to<WebFormElement>();
+  ASSERT_FALSE(web_form.isNull());
+
+  FormData form;
+  EXPECT_TRUE(WebFormElementToFormData(web_form, WebFormControlElement(),
+                                       EXTRACT_NONE, &form, nullptr));
+
+  ASSERT_EQ(3U, form.fields.size());
+
+  EXPECT_FALSE(form.fields[0].should_autocomplete);
+  EXPECT_TRUE(form.fields[1].should_autocomplete);
+  EXPECT_TRUE(form.fields[2].should_autocomplete);
+}
+
 TEST_F(FormAutofillTest, ExtractForms) {
   ExpectJohnSmithLabels(
       "<FORM name='TestForm' action='http://cnn.com' method='post'>"
diff --git a/chrome/renderer/chrome_content_renderer_client.cc b/chrome/renderer/chrome_content_renderer_client.cc
index 0db8e41..65f743f 100644
--- a/chrome/renderer/chrome_content_renderer_client.cc
+++ b/chrome/renderer/chrome_content_renderer_client.cc
@@ -1122,7 +1122,8 @@
   }
 
   if (error_description)
-    *error_description = LocalizedError::GetErrorDetails(error, is_post);
+    *error_description = LocalizedError::GetErrorDetails(error.domain.utf8(),
+                                                         error.reason, is_post);
 }
 
 bool ChromeContentRendererClient::RunIdleHandlerWhenWidgetsHidden() {
diff --git a/chrome/renderer/chrome_render_process_observer.cc b/chrome/renderer/chrome_render_process_observer.cc
index 543032b..72c985b 100644
--- a/chrome/renderer/chrome_render_process_observer.cc
+++ b/chrome/renderer/chrome_render_process_observer.cc
@@ -318,7 +318,8 @@
   base::FieldTrial* trial =
       base::FieldTrialList::CreateFieldTrial(field_trial_name, group_name);
   // TODO(mef): Remove this check after the investigation of 359406 is complete.
-  CHECK(trial) << field_trial_name << ":" << group_name;
+  CHECK(trial) << field_trial_name << ":" << group_name << "=>"
+               << base::FieldTrialList::FindFullName(field_trial_name);
   // Ensure the trial is marked as "used" by calling group() on it if it is
   // marked as activated.
   trial->group();
diff --git a/chrome/renderer/resources/neterror.html b/chrome/renderer/resources/neterror.html
index f1fba59..f3807438 100644
--- a/chrome/renderer/resources/neterror.html
+++ b/chrome/renderer/resources/neterror.html
@@ -41,13 +41,13 @@
             class="gray-button text-button"
             onclick="showOfflinePagesButtonClick()"
             jsselect="showOfflinePagesButton"
-            jscontent="msg" jsvalues="title:title">
+            jscontent="msg">
         </button>
         <button id="show-offline-copy-button"
             class="blue-button text-button"
             onclick="showOfflineCopyButtonClick()"
             jsselect="showOfflineCopyButton"
-            jscontent="msg" jsvalues="title:title; .primary:primary">
+            jscontent="msg" jsvalues=".primary:primary">
         </button>
       </div>
       <button id="details-button" class="text-button small-link"
diff --git a/chrome/sync_integration_tests.isolate b/chrome/sync_integration_tests.isolate
index 295da53..4bb4ad6 100644
--- a/chrome/sync_integration_tests.isolate
+++ b/chrome/sync_integration_tests.isolate
@@ -76,6 +76,7 @@
       'variables': {
         'files': [
           '<(PRODUCT_DIR)/chrome_elf.dll',
+          '<(PRODUCT_DIR)/crashpad_handler.exe',
         ],
       },
     }],
diff --git a/chrome/telemetry_unittests.isolate b/chrome/telemetry_unittests.isolate
index fb8c401..14b5d8a 100644
--- a/chrome/telemetry_unittests.isolate
+++ b/chrome/telemetry_unittests.isolate
@@ -15,10 +15,6 @@
           '../testing/scripts/common.py',
           '../testing/scripts/run_telemetry_as_googletest.py',
         ],
-      }
-    }],
-    ['OS=="mac"', {
-      'variables': {
         'command': [
           '../testing/scripts/run_telemetry_as_googletest.py',
           '../tools/telemetry/run_tests',
@@ -28,20 +24,5 @@
         ],
       },
     }],
-    ['OS=="win"', {
-      'variables': {
-        'command': [
-          '../testing/scripts/run_telemetry_as_googletest.py',
-          '../tools/telemetry/run_tests',
-          '-v',
-          '--chrome-root',
-          '..',
-          # crbug.com/559154
-          # TODO(nednguyen): Remove --jobs=1 once the bug is fixed to speed up
-          # the test run.
-          '--job=1',
-        ],
-      },
-    }],
   ]
 }
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 32a0caaa..3670d55 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -197,7 +197,11 @@
     ]
   }
   if (is_win) {
-    public_deps += [ "//third_party/wtl" ]
+    sources += [ "//chrome/app/chrome_crash_reporter_client.cc" ]
+    public_deps += [
+      "//components/crash/content/app",
+      "//third_party/wtl",
+    ]
     if (use_aura) {
       public_deps += [
         "//win8:test_registrar_constants",
@@ -1667,12 +1671,14 @@
         [ "../browser/download/download_request_infobar_delegate_unittest.cc" ]
   }
 
-  if (!is_android && !is_ios) {
+  if (!is_ios) {
     deps += [ ":unit_tests_js" ]
-    sources += rebase_path(
-            chrome_tests_unit_gypi_values.chrome_unit_tests_non_mobile_sources,
-            ".",
-            "//chrome")
+    if (!is_android) {
+      sources += rebase_path(
+              chrome_tests_unit_gypi_values.chrome_unit_tests_non_mobile_sources,
+              ".",
+              "//chrome")
+    }
   }
 
   if (is_ios || is_chromeos) {
@@ -2110,6 +2116,11 @@
             chrome_tests_unit_gypi_values.chrome_unit_tests_app_list_chromeos_sources,
             ".",
             "//chrome")
+    sources += rebase_path(
+            chrome_tests_unit_gypi_values.chrome_unit_tests_app_list_chromeos_arc_sources,
+            ".",
+            "//chrome")
+    deps += [ "//components/arc:arc_test_support" ]
   }
   if (enable_plugins && !enable_plugin_installation) {
     sources -= [ "../browser/plugins/plugin_installer_unittest.cc" ]
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/ChromeActivityTestCaseBase.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/ChromeActivityTestCaseBase.java
index 11ef462..006b0d5 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/ChromeActivityTestCaseBase.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/ChromeActivityTestCaseBase.java
@@ -17,8 +17,6 @@
 import android.view.View;
 import android.widget.ListView;
 
-import junit.framework.Assert;
-
 import org.chromium.base.PerfTraceEvent;
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.annotations.SuppressFBWarnings;
@@ -464,33 +462,26 @@
 
         startActivityCompletely(intent);
 
-        assertTrue("Tab never selected/initialized.",
-                CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
-                    @Override
-                    public boolean isSatisfied() {
-                        return getActivity().getActivityTab() != null;
-                    }
-                }));
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria("Tab never selected/initialized.") {
+            @Override
+            public boolean isSatisfied() {
+                return getActivity().getActivityTab() != null;
+            }
+        });
         Tab tab = getActivity().getActivityTab();
 
         ChromeTabUtils.waitForTabPageLoaded(tab, (String) null);
 
         if (!isDocumentMode && tab != null && NewTabPage.isNTPUrl(tab.getUrl())) {
-            boolean ntpReady = NewTabPageTestUtils.waitForNtpLoaded(tab);
-            if (!ntpReady && tab.isShowingSadTab()) {
-                fail("Renderer crashed before NTP finished loading. "
-                        + "Look at logcat for renderer stack dump.");
-            }
-            assertTrue("Initial NTP never fully loaded.", ntpReady);
+            NewTabPageTestUtils.waitForNtpLoaded(tab);
         }
 
-        assertTrue("Deferred startup never completed",
-                CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
-                    @Override
-                    public boolean isSatisfied() {
-                        return DeferredStartupHandler.getInstance().isDeferredStartupComplete();
-                    }
-                }));
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria("Deferred startup never completed") {
+            @Override
+            public boolean isSatisfied() {
+                return DeferredStartupHandler.getInstance().isDeferredStartupComplete();
+            }
+        });
 
         assertNotNull(tab);
         assertNotNull(tab.getView());
@@ -588,8 +579,7 @@
         }
 
         ChromeTabUtils.waitForTabPageLoaded(tab, (String) null);
-        Assert.assertTrue("NTP never fully loaded.",
-                NewTabPageTestUtils.waitForNtpLoaded(tab));
+        NewTabPageTestUtils.waitForNtpLoaded(tab);
         getInstrumentation().waitForIdleSync();
         Log.d(TAG, "newIncognitoTabFromMenu <<");
     }
@@ -702,13 +692,13 @@
                 }
 
                 // Wait for suggestions to show up.
-                assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
+                CriteriaHelper.pollForCriteria(new Criteria() {
                     @Override
                     public boolean isSatisfied() {
                         return ((LocationBarLayout) getActivity().findViewById(
                                 R.id.location_bar)).getSuggestionList() != null;
                     }
-                }, 3000, 10));
+                }, 3000, 10);
                 final ListView suggestionListView = locationBar.getSuggestionList();
                 OmniboxResultItem popupItem = (OmniboxResultItem) suggestionListView
                         .getItemAtPosition(0);
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/MultiActivityTestBase.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/MultiActivityTestBase.java
index ab5b3db..d71c9d8 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/MultiActivityTestBase.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/MultiActivityTestBase.java
@@ -174,14 +174,14 @@
         final Tab tab = activity.getActivityTab();
         assert tab != null;
 
-        assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 if (!tab.isLoadingAndRenderingDone()) return false;
                 if (!TextUtils.equals(expectedTitle, tab.getTitle())) return false;
                 return true;
             }
-        }));
+        });
     }
 
     /**
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/ActivityUtils.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/ActivityUtils.java
index 825b1df..19eab5d 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/ActivityUtils.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/ActivityUtils.java
@@ -26,12 +26,13 @@
     /**
      * Waits for a particular fragment to be present on a given activity.
      */
-    private static class FragmentPresentCriteria implements Criteria {
+    private static class FragmentPresentCriteria extends Criteria {
 
         private final Activity mActivity;
         private final String mFragmentTag;
 
         public FragmentPresentCriteria(Activity activity, String fragmentTag) {
+            super(String.format("Could not locate the fragment with tag '%s'", fragmentTag));
             mActivity = activity;
             mFragmentTag = fragmentTag;
         }
@@ -96,9 +97,8 @@
     @SuppressWarnings({"unchecked", "TypeParameterUnusedInFormals"})
     public static <T> T waitForFragment(Activity activity, String fragmentTag)
             throws InterruptedException {
-        Assert.assertTrue(String.format("Could not locate the fragment with tag '%s'", fragmentTag),
-                CriteriaHelper.pollForCriteria(new FragmentPresentCriteria(activity, fragmentTag),
-                        ACTIVITY_START_TIMEOUT_MS, CONDITION_POLL_INTERVAL_MS));
+        CriteriaHelper.pollForCriteria(new FragmentPresentCriteria(activity, fragmentTag),
+                ACTIVITY_START_TIMEOUT_MS, CONDITION_POLL_INTERVAL_MS);
         return (T) activity.getFragmentManager().findFragmentByTag(fragmentTag);
     }
 
@@ -117,15 +117,12 @@
     public static <T extends Fragment> T waitForFragmentToAttach(
             final Preferences activity, final Class<T> fragmentClass)
             throws InterruptedException {
-        boolean isFragmentAttached = CriteriaHelper.pollForCriteria(
-                new Criteria() {
-                    @Override
-                    public boolean isSatisfied() {
-                        return fragmentClass.isInstance(activity.getFragmentForTest());
-                    }
-                },
-                ACTIVITY_START_TIMEOUT_MS, CONDITION_POLL_INTERVAL_MS);
-        Assert.assertTrue("Could not find fragment " + fragmentClass, isFragmentAttached);
+        CriteriaHelper.pollForCriteria(new Criteria("Could not find fragment " + fragmentClass) {
+            @Override
+            public boolean isSatisfied() {
+                return fragmentClass.isInstance(activity.getFragmentForTest());
+            }
+        }, ACTIVITY_START_TIMEOUT_MS, CONDITION_POLL_INTERVAL_MS);
         return (T) activity.getFragmentForTest();
     }
 }
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/ApplicationData.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/ApplicationData.java
index d834291..2bbcb56 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/ApplicationData.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/ApplicationData.java
@@ -36,12 +36,10 @@
      * When this is invoked from tests, the target context from the instrumentation must be used.
      *
      * @param targetContext the target Context.
-     *
-     * @return Whether clearing the application data was successful.
      */
-    public static boolean clearAppData(Context targetContext) throws InterruptedException {
+    public static void clearAppData(Context targetContext) throws InterruptedException {
         final String appDir = getAppDirFromTargetContext(targetContext);
-        return CriteriaHelper.pollForCriteria(
+        CriteriaHelper.pollForCriteria(
                 new Criteria() {
                     private boolean mDataRemoved = false;
 
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/ApplicationTestUtils.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/ApplicationTestUtils.java
index e3d2288..6ad36689 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/ApplicationTestUtils.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/ApplicationTestUtils.java
@@ -36,7 +36,7 @@
             throws Exception {
         if (clearAppData) {
             // Clear data and remove any tasks listed in Android's Overview menu between test runs.
-            Assert.assertTrue("Unable to clear the app data", clearAppData(context));
+            clearAppData(context);
             if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                 finishAllChromeTasks(context);
             }
@@ -70,10 +70,9 @@
      * Clear all files and folders in the Chrome application directory except 'lib'.
      * The 'cache' directory is recreated as an empty directory.
      * @param context Target instrumentation context.
-     * @return Whether clearing the application data was successful.
      */
-    public static boolean clearAppData(Context context) throws InterruptedException {
-        return ApplicationData.clearAppData(context);
+    public static void clearAppData(Context context) throws InterruptedException {
+        ApplicationData.clearAppData(context);
     }
 
     /** Send the user to the Android home screen. */
@@ -97,25 +96,25 @@
 
     /** Waits until Chrome is in the background. */
     public static void waitUntilChromeInBackground() throws Exception {
-        Assert.assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
+        CriteriaHelper.pollForCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 int state = ApplicationStatus.getStateForApplication();
                 return state == ApplicationState.HAS_STOPPED_ACTIVITIES
                         || state == ApplicationState.HAS_DESTROYED_ACTIVITIES;
             }
-        }));
+        });
     }
 
     /** Waits until Chrome is in the foreground. */
     public static void waitUntilChromeInForeground() throws Exception {
-        Assert.assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
+        CriteriaHelper.pollForCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 int state = ApplicationStatus.getStateForApplication();
                 return state == ApplicationState.HAS_RUNNING_ACTIVITIES;
             }
-        }));
+        });
     }
 
     /** Finishes all tasks Chrome has listed in Android's Overview. */
@@ -128,18 +127,17 @@
             task.finishAndRemoveTask();
         }
 
-        Assert.assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
+        CriteriaHelper.pollForCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return getNumChromeTasks(context) == 0;
             }
-        }));
+        });
     }
 
     /** Counts how many tasks Chrome has listed in Android's Overview. */
     @TargetApi(Build.VERSION_CODES.LOLLIPOP)
     public static int getNumChromeTasks(Context context) {
-        int count = 0;
         ActivityManager activityManager =
                 (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
         return activityManager.getAppTasks().size();
@@ -163,16 +161,16 @@
     public static void assertWaitForPageScaleFactorMatch(final ChromeActivity activity,
             final float expectedScale, boolean waitLongerForLoad) throws InterruptedException {
         long waitTimeInMs = waitLongerForLoad ? 10000 : CriteriaHelper.DEFAULT_MAX_TIME_TO_POLL;
-        boolean scaleFactorMatch = CriteriaHelper.pollForCriteria(new Criteria() {
+        CriteriaHelper.pollForCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 if (activity.getCurrentContentViewCore() == null) return false;
 
+                updateFailureReason("Expecting scale factor of: " + expectedScale + ", got: "
+                        + activity.getCurrentContentViewCore().getScale());
                 return Math.abs(activity.getCurrentContentViewCore().getScale() - expectedScale)
                         < FLOAT_EPSILON;
             }
         }, waitTimeInMs, CriteriaHelper.DEFAULT_POLLING_INTERVAL);
-        Assert.assertTrue("Expecting scale factor of: " + expectedScale + ", got: "
-                    + activity.getCurrentContentViewCore().getScale(), scaleFactorMatch);
     }
 }
\ No newline at end of file
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/BookmarkTestUtils.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/BookmarkTestUtils.java
index 6d44171b..82f0b550 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/BookmarkTestUtils.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/BookmarkTestUtils.java
@@ -282,12 +282,12 @@
 
     private static void checkCriteria(String message, final Callable<Boolean> criteria)
             throws InterruptedException {
-        Assert.assertTrue(message, CriteriaHelper.pollForCriteria(new Criteria() {
+        CriteriaHelper.pollForCriteria(new Criteria(message) {
             @Override
             public boolean isSatisfied() {
                 return ThreadUtils.runOnUiThreadBlockingNoException(criteria);
             }
-        }));
+        });
     }
 
     /**
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/ChromeTabUtils.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/ChromeTabUtils.java
index 5f1ee5c..3db694c 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/ChromeTabUtils.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/ChromeTabUtils.java
@@ -256,8 +256,7 @@
 
         Tab tab = activity.getActivityTab();
         waitForTabPageLoaded(tab, (String) null);
-        Assert.assertTrue("NTP never fully loaded.",
-                NewTabPageTestUtils.waitForNtpLoaded(tab));
+        NewTabPageTestUtils.waitForNtpLoaded(tab);
         instrumentation.waitForIdleSync();
         Log.d(TAG, "newTabFromMenu <<");
     }
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/NewTabPageTestUtils.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/NewTabPageTestUtils.java
index c76ba1a..de88ad0 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/NewTabPageTestUtils.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/NewTabPageTestUtils.java
@@ -23,11 +23,10 @@
      * Waits for the NTP owned by the passed in tab to be fully loaded.
      *
      * @param tab The tab to be monitored for NTP loading.
-     * @return Whether the NTP has fully loaded.
      */
     @TargetApi(Build.VERSION_CODES.LOLLIPOP)
-    public static boolean waitForNtpLoaded(final Tab tab) throws InterruptedException {
-        return CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+    public static void waitForNtpLoaded(final Tab tab) throws InterruptedException {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria("NTP never fully loaded") {
             @Override
             public boolean isSatisfied() {
                 if (!tab.isIncognito()) {
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/OmniboxTestUtils.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/OmniboxTestUtils.java
index 690d432d..0b3eec6 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/OmniboxTestUtils.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/OmniboxTestUtils.java
@@ -229,9 +229,9 @@
             throws InterruptedException {
         for (int i = 0; i < times; i++) {
             toggleUrlBarFocus(urlBar, true);
-            Assert.assertTrue(waitForFocusAndKeyboardActive(urlBar, true));
+            waitForFocusAndKeyboardActive(urlBar, true);
             toggleUrlBarFocus(urlBar, false);
-            Assert.assertTrue(waitForFocusAndKeyboardActive(urlBar, false));
+            waitForFocusAndKeyboardActive(urlBar, false);
         }
     }
 
@@ -284,11 +284,10 @@
      *
      * @param urlBar The UrlBar whose focus is being inspected.
      * @param active Whether the UrlBar is expected to have focus or not.
-     * @return Whether the UrlBar had the requested focus state.
      */
-    public static boolean waitForFocusAndKeyboardActive(final UrlBar urlBar, final boolean active)
+    public static void waitForFocusAndKeyboardActive(final UrlBar urlBar, final boolean active)
             throws InterruptedException {
-        return CriteriaHelper.pollForCriteria(new Criteria() {
+        CriteriaHelper.pollForCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return (doesUrlBarHaveFocus(urlBar) == active)
@@ -301,11 +300,10 @@
      * Waits for a non-empty list of omnibox suggestions is shown.
      *
      * @param locationBar The LocationBar who owns the suggestions.
-     * @return Whether the suggestions were shown.
      */
-    public static boolean waitForOmniboxSuggestions(final LocationBarLayout locationBar)
+    public static void waitForOmniboxSuggestions(final LocationBarLayout locationBar)
             throws InterruptedException {
-        return CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 LocationBarLayout.OmniboxSuggestionsList suggestionsList =
@@ -321,12 +319,11 @@
      * Waits for a suggestion list to be shown with a specified number of entries.
      * @param locationBar The LocationBar who owns the suggestions.
      * @param expectedCount The number of suggestions expected to be shown.
-     * @return Whether the suggestions were shown.
      */
-    public static boolean waitForOmniboxSuggestions(
+    public static void waitForOmniboxSuggestions(
             final LocationBarLayout locationBar, final int expectedCount)
             throws InterruptedException {
-        return CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 LocationBarLayout.OmniboxSuggestionsList suggestionsList =
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/OverviewModeBehaviorWatcher.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/OverviewModeBehaviorWatcher.java
index 9a8a2816..e537cd6 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/OverviewModeBehaviorWatcher.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/OverviewModeBehaviorWatcher.java
@@ -4,8 +4,6 @@
 
 package org.chromium.chrome.test.util;
 
-import junit.framework.Assert;
-
 import org.chromium.chrome.browser.compositor.layouts.OverviewModeBehavior;
 import org.chromium.chrome.browser.compositor.layouts.OverviewModeBehavior.OverviewModeObserver;
 import org.chromium.content.browser.test.util.Criteria;
@@ -23,7 +21,17 @@
     private final Criteria mCriteria = new Criteria() {
         @Override
         public boolean isSatisfied() {
-            return !mWaitingForShow && !mWaitingForHide;
+            if (mWaitingForShow) {
+                updateFailureReason(
+                        "OverviewModeObserver#onOverviewModeFinishedShowing() not called.");
+                return false;
+            }
+            if (mWaitingForHide) {
+                updateFailureReason(
+                        "OverviewModeObserver#onOverviewModeFinishedHiding() not called.");
+                return false;
+            }
+            return true;
         }
     };
 
@@ -67,14 +75,7 @@
      */
     public void waitForBehavior() throws InterruptedException {
         try {
-            if (!CriteriaHelper.pollForUIThreadCriteria(mCriteria)) {
-                Assert.assertFalse(
-                        "OverviewModeObserver#onOverviewModeFinishedShowing() not called.",
-                        mWaitingForShow);
-                Assert.assertFalse(
-                        "OverviewModeObserver#onOverviewModeFinishedHiding() not called.",
-                        mWaitingForHide);
-            }
+            CriteriaHelper.pollForUIThreadCriteria(mCriteria);
         } finally {
             mOverviewModeBehavior.removeOverviewModeObserver(this);
         }
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/PrerenderTestHelper.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/PrerenderTestHelper.java
index b3e822c..0361ece1 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/PrerenderTestHelper.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/PrerenderTestHelper.java
@@ -48,12 +48,16 @@
      */
     public static boolean waitForPrerenderUrl(final Tab tab, final String url,
             boolean shortTimeout) throws InterruptedException {
-        CriteriaHelper.pollForCriteria(new Criteria() {
-            @Override
-            public boolean isSatisfied() {
-                return hasTabPrerenderedUrl(tab, url);
-            }
-        }, shortTimeout ? SHORT_TIMEOUT_MS : WAIT_FOR_RESPONSE_MS, UI_DELAY_MS);
+        try {
+            CriteriaHelper.pollForCriteria(new Criteria() {
+                @Override
+                public boolean isSatisfied() {
+                    return hasTabPrerenderedUrl(tab, url);
+                }
+            }, shortTimeout ? SHORT_TIMEOUT_MS : WAIT_FOR_RESPONSE_MS, UI_DELAY_MS);
+        } catch (AssertionError e) {
+            // TODO(tedchoc): This is horrible and should never timeout to determine success.
+        }
 
         return hasTabPrerenderedUrl(tab, url);
     }
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/TabLoadObserver.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/TabLoadObserver.java
index 3b0be21..76a575d 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/TabLoadObserver.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/TabLoadObserver.java
@@ -6,8 +6,6 @@
 
 import android.text.TextUtils;
 
-import junit.framework.Assert;
-
 import org.chromium.base.ThreadUtils;
 import org.chromium.chrome.browser.tab.EmptyTabObserver;
 import org.chromium.chrome.browser.tab.Tab;
@@ -16,7 +14,6 @@
 import org.chromium.content_public.browser.LoadUrlParams;
 
 import java.util.Locale;
-import java.util.concurrent.atomic.AtomicReference;
 
 /**
  * Monitors that a Tab starts loading and stops loading a URL.
@@ -64,27 +61,25 @@
      * @param maxAllowedTime The maximum time this will wait for the page to load.
      */
     public void assertLoaded(long maxAllowedTime) throws InterruptedException {
-        final AtomicReference<String> failureReason = new AtomicReference<>();
-
         Criteria loadedCriteria = new Criteria() {
             @Override
             public boolean isSatisfied() {
                 if (!mTabLoadStarted) {
-                    failureReason.set("load started never called");
+                    updateFailureReason("load started never called");
                     return false;
                 }
                 if (!mTabLoadStopped) {
-                    failureReason.set("load stopped never called");
+                    updateFailureReason("load stopped never called");
                     return false;
                 }
                 if (!mTab.isLoadingAndRenderingDone()) {
-                    failureReason.set("load and rendering never completed");
+                    updateFailureReason("load and rendering never completed");
                     return false;
                 }
 
                 String title = mTab.getTitle();
                 if (mExpectedTitle != null && !TextUtils.equals(mExpectedTitle, title)) {
-                    failureReason.set(String.format(
+                    updateFailureReason(String.format(
                             Locale.ENGLISH,
                             "title did not match -- expected: \"%s\", actual \"%s\"",
                             mExpectedTitle, title));
@@ -92,29 +87,26 @@
                 }
                 if (mExpectedScale != null) {
                     if (mTab.getContentViewCore() == null) {
-                        failureReason.set("tab has no content view core");
+                        updateFailureReason("tab has no content view core");
                         return false;
                     }
 
                     float scale = mTab.getContentViewCore().getScale();
                     if (Math.abs(mExpectedScale - scale) >= FLOAT_EPSILON) {
-                        failureReason.set(String.format(
+                        updateFailureReason(String.format(
                                 Locale.ENGLISH,
                                 "scale did not match with allowed epsilon -- "
                                 + "expected: \"%f\", actual \"%f\"", mExpectedScale, scale));
                         return false;
                     }
                 }
-                failureReason.set(null);
+                updateFailureReason(null);
                 return true;
             }
         };
 
-        boolean result = CriteriaHelper.pollForUIThreadCriteria(
+        CriteriaHelper.pollForUIThreadCriteria(
                 loadedCriteria, maxAllowedTime, CriteriaHelper.DEFAULT_POLLING_INTERVAL);
-        if (!result) {
-            Assert.fail("Tab not fully loaded because: " + failureReason.get());
-        }
     }
 
     /**
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/contextmenu/ContextMenuUtils.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/contextmenu/ContextMenuUtils.java
index 438477d..e2afc11 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/contextmenu/ContextMenuUtils.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/contextmenu/ContextMenuUtils.java
@@ -162,12 +162,11 @@
             }
         });
 
-        Assert.assertTrue("Activity did not regain focus.",
-                CriteriaHelper.pollForCriteria(new Criteria() {
-                    @Override
-                    public boolean isSatisfied() {
-                        return testCase.getActivity().hasWindowFocus();
-                    }
-                }));
+        CriteriaHelper.pollForCriteria(new Criteria("Activity did not regain focus.") {
+            @Override
+            public boolean isSatisfied() {
+                return testCase.getActivity().hasWindowFocus();
+            }
+        });
     }
 }
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/sync/SyncTestUtil.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/sync/SyncTestUtil.java
index c31e302..bde367f 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/sync/SyncTestUtil.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/sync/SyncTestUtil.java
@@ -67,13 +67,13 @@
     public static void triggerSyncAndWaitForCompletion() throws InterruptedException {
         final long oldSyncTime = getCurrentSyncTime();
         triggerSync();
-        boolean syncCompleted = CriteriaHelper.pollForCriteria(new Criteria() {
+        CriteriaHelper.pollForCriteria(new Criteria(
+                "Timed out waiting for sync cycle to complete.") {
             @Override
             public boolean isSatisfied() {
                 return getCurrentSyncTime() > oldSyncTime;
             }
         }, TIMEOUT_MS, INTERVAL_MS);
-        Assert.assertTrue("Timed out waiting for sync cycle to complete.", syncCompleted);
     }
 
     private static long getCurrentSyncTime() {
@@ -89,13 +89,13 @@
      * Waits for sync to become active.
      */
     public static void waitForSyncActive() throws InterruptedException {
-        Assert.assertTrue("Timed out waiting for sync to become active.",
-                CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
-                    @Override
-                    public boolean isSatisfied() {
-                        return ProfileSyncService.get().isSyncActive();
-                    }
-                }, TIMEOUT_MS, INTERVAL_MS));
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria(
+                "Timed out waiting for sync to become active.") {
+            @Override
+            public boolean isSatisfied() {
+                return ProfileSyncService.get().isSyncActive();
+            }
+        }, TIMEOUT_MS, INTERVAL_MS);
     }
 
     /**
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/tabmodel/document/TestInitializationObserver.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/tabmodel/document/TestInitializationObserver.java
index 7f20edc..7b511eb2 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/tabmodel/document/TestInitializationObserver.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/tabmodel/document/TestInitializationObserver.java
@@ -4,8 +4,6 @@
 
 package org.chromium.chrome.test.util.browser.tabmodel.document;
 
-import static junit.framework.Assert.assertTrue;
-
 import org.chromium.base.ThreadUtils;
 import org.chromium.chrome.browser.tabmodel.document.DocumentTabModel;
 import org.chromium.content.browser.test.util.Criteria;
@@ -52,11 +50,11 @@
             }
         });
 
-        assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
+        CriteriaHelper.pollForCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return observer.mIsReady;
             }
-        }));
+        });
     }
 }
\ No newline at end of file
diff --git a/chrome/test/base/chrome_test_launcher.cc b/chrome/test/base/chrome_test_launcher.cc
index a1b317e..6e59b804 100644
--- a/chrome/test/base/chrome_test_launcher.cc
+++ b/chrome/test/base/chrome_test_launcher.cc
@@ -19,7 +19,9 @@
 #include "chrome/common/chrome_switches.h"
 #include "chrome/test/base/chrome_test_suite.h"
 #include "chrome/test/base/test_switches.h"
+#include "components/crash/content/app/crashpad.h"
 #include "content/public/app/content_main.h"
+#include "content/public/common/content_switches.h"
 #include "content/public/test/test_launcher.h"
 #include "content/public/test/test_utils.h"
 #include "ui/base/test/ui_controls.h"
@@ -40,7 +42,7 @@
 #include "ash/test/ui_controls_factory_ash.h"
 #endif
 
-#if defined(OS_LINUX) || defined(OS_ANDROID)
+#if defined(OS_LINUX) || defined(OS_ANDROID) || defined(OS_WIN)
 #include "chrome/app/chrome_crash_reporter_client.h"
 #endif
 
@@ -112,14 +114,22 @@
   chrome_browser_application_mac::RegisterBrowserCrApp();
 #endif
 
-#if defined(OS_LINUX) || defined(OS_ANDROID)
-  // We leak this pointer intentionally. The breakpad client needs to outlive
+#if defined(OS_LINUX) || defined(OS_ANDROID) || defined(OS_WIN)
+  // We leak this pointer intentionally. The crash client needs to outlive
   // all other code.
   ChromeCrashReporterClient* crash_client = new ChromeCrashReporterClient();
   ANNOTATE_LEAKING_OBJECT_PTR(crash_client);
   crash_reporter::SetCrashReporterClient(crash_client);
 #endif
 
+#if defined(OS_WIN)
+  base::CommandLine::Init(0, nullptr);
+  std::string process_type =
+      base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+          switches::kProcessType);
+  crash_reporter::InitializeCrashpad(process_type.empty(), process_type);
+#endif
+
   ChromeTestLauncherDelegate launcher_delegate(runner);
   return content::LaunchTests(&launcher_delegate, default_jobs, argc, argv);
 }
diff --git a/chrome/test/base/chrome_test_suite.cc b/chrome/test/base/chrome_test_suite.cc
index 6581d13..90e4331 100644
--- a/chrome/test/base/chrome_test_suite.cc
+++ b/chrome/test/base/chrome_test_suite.cc
@@ -16,13 +16,14 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/common/chrome_constants.h"
 #include "chrome/common/chrome_paths.h"
+#include "chrome/common/features.h"
 #include "chrome/common/url_constants.h"
 #include "components/content_settings/core/common/content_settings_pattern.h"
 #include "content/public/test/test_launcher.h"
 #include "extensions/common/constants.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
 #include "base/android/jni_android.h"
 #include "chrome/browser/android/chrome_jni_registrar.h"
 #endif
@@ -82,7 +83,7 @@
     PathService::Override(base::DIR_MODULE, browser_dir_);
   }
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(ANDROID_JAVA_UI)
   ASSERT_TRUE(chrome::android::RegisterBrowserJNI(
       base::android::AttachCurrentThread()));
 #endif
diff --git a/chrome/test/data/chromeos/app_mode/multi_app_kiosk/src/primary_app/key.pem b/chrome/test/data/chromeos/app_mode/multi_app_kiosk/src/primary_app/key.pem
new file mode 100644
index 0000000..fac381c
--- /dev/null
+++ b/chrome/test/data/chromeos/app_mode/multi_app_kiosk/src/primary_app/key.pem
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDmJvQFpDnngGBy
+iIEpjw4RfxRNS/keOHz54Qjh5M5PKAlZPHZmxhEsrg8FwAQWiZP6/zrtPFAVzalU
+WJJjBz5TLUmGY8BLvg3nBEHtcQ6qTcJHRms96wi4gM76DIZVdjh5SW0c5XY41CPP
+alfr8Xtdhg+Y2d+Em5jjS33JMXQgilR34cpKzj4KfPvzX4nQULc0DhdnRshrWzZq
+Np3vjZYdt0D7WfJR52RUsQHZxIuY5oKxv/IRG43/NENx1QdtmkMdVZxcv59F+zg8
+qC7HxsLlSo4A0mdYR/9Qldqkxdl3j1FqEDF+XLZHntmpydCbt9GyddmIwSeiSob5
+5Yka4EwLAgMBAAECggEBAIMIKmYL2euzazXKAb9nctsDPsvDNVG/V2fsduIlIlBu
+uuPTSJW6royBjIv5hlpOebGtHh9y9yVysbUTuEQpG5K/ddzNbe2xhri/88j7VR4g
+pzttHCFkbtKcgzpZZyHA7OYgp76L5YL1RG4SXXw3P8U/TiH36QnWjHTbxgGF5lef
+VZCM/f6p73JySbvgmkoUW2fi757bEz3Tb2CWiNbdutfFBnjm9Vh0Mp/aF3RJM7tZ
+vQTU3yAcXKqhtqLXQ6uT+D7zZfgTImZnRLwOnIQRz0xEIIbjU4/CNZdMT3HbGsbC
+kK+9Exru8j61epCwFUfiaixq71CqHggyIplBoTonMgECgYEA9PHUCj/VAFHPYqZZ
+pUHX/6+A0Rl7QcmuQ5xP0QzQcE8OXLZEUtWmRUDs4Vx0qQRKFDU4s2mj1b/PETl4
+dl36tPNoZb74GbvGisb5ZU26d1II/+3axJ5AcMylHRyyQt2SxSFggSaLS4VWYClu
+7uDDrG87dC7JNa66oj0P88Sf5C8CgYEA8Io1K4tbuVrqqTsrEJ0UyDrLBw9eSIvk
+2BnTomt517fTt368Kq/IutKw3aV8ZkgdJIGswua67OSC08faw/piRgUuYxtpXvFU
+b74Au0wQHUM0g3W9fe4iTjsJEIkaFpa2ITxL/eaDmr9gO4t6rRepl8Sewulh444E
+ZxMXDF04MuUCgYBSySEHTcep0fyrtNl7lyNv0VtSULBt7cIuK7h2SURxkOajwx6Y
+eIk3wtfM2zi6ny6CYfKGAOBUr/1GLwxdxSmk2tef+8lSuTpDUTidWoX5KgrMpRFZ
+frr85M2xZy+Ale6zHbLGM8bEgY5N9fL+XY0EzJtliyKKOEHv739ivkPkFQKBgAJy
+taXSzkUtqrO8OWz63EpJZuWUf3YnjlWwtZmylFPguBPnA00/6sAUAt7On1x/IWTM
+uRBmvsJIdRhosU5LTxK9XMJ/dewUcrKMcX92f7d8hp1L5njQoqK/MRFtA8n1ELd3
+4KId5Xr+taEFg2MdmYlE5ATB0VA6ksrlw9dJX5gNAoGAGAo7B78o1f3BGuBqgYiM
+irmpDiUbx9bSm1En1hs9/D7jeAMay+omroTaBnEaycFjOY3baeMNuDp8myGYzeKd
+Z6CaDi9o0MJnbOX32DNNLyhrg67tlH/mwO1D6+vKnzIywuS4bWuW0CbDRCSsG9Mh
+irtGu/xwo/nI8U2ZI8bDXyE=
+-----END PRIVATE KEY-----
diff --git a/chrome/test/data/chromeos/app_mode/multi_app_kiosk/src/primary_app/v1/manifest.json b/chrome/test/data/chromeos/app_mode/multi_app_kiosk/src/primary_app/v1/manifest.json
index 60e4b2c..47467ba 100644
--- a/chrome/test/data/chromeos/app_mode/multi_app_kiosk/src/primary_app/v1/manifest.json
+++ b/chrome/test/data/chromeos/app_mode/multi_app_kiosk/src/primary_app/v1/manifest.json
@@ -15,8 +15,8 @@
   "kiosk_enabled": true,
   "offline_enabled": true,
   "kiosk_secondary_apps": [
-    {"id": "ihplaomghjbeafnpnjkhppmfpnmdihgd"},
-    {"id": "fiehokkcgaojmbhfhlpiheggjhaedjoc"}
+    {"id": "emnbflhfbllbehnpjmjddklbkeeoaaeg"},
+    {"id": "blmjgfbajihimkjmepbhgmjbopjchlda"}
   ],
   "permissions": [
     "power"
diff --git a/chrome/test/data/chromeos/app_mode/multi_app_kiosk/src/primary_app/v2/manifest.json b/chrome/test/data/chromeos/app_mode/multi_app_kiosk/src/primary_app/v2/manifest.json
index 55f7f6f..5712db1 100644
--- a/chrome/test/data/chromeos/app_mode/multi_app_kiosk/src/primary_app/v2/manifest.json
+++ b/chrome/test/data/chromeos/app_mode/multi_app_kiosk/src/primary_app/v2/manifest.json
@@ -15,7 +15,7 @@
   "kiosk_enabled": true,
   "offline_enabled": true,
   "kiosk_secondary_apps": [    
-    {"id": "fiehokkcgaojmbhfhlpiheggjhaedjoc"}
+    {"id": "blmjgfbajihimkjmepbhgmjbopjchlda"}
   ],
   "permissions": [
     "power"
diff --git a/chrome/test/data/chromeos/app_mode/multi_app_kiosk/src/primary_app/v24/manifest.json b/chrome/test/data/chromeos/app_mode/multi_app_kiosk/src/primary_app/v24/manifest.json
index cb698e6..36360a9 100644
--- a/chrome/test/data/chromeos/app_mode/multi_app_kiosk/src/primary_app/v24/manifest.json
+++ b/chrome/test/data/chromeos/app_mode/multi_app_kiosk/src/primary_app/v24/manifest.json
@@ -15,6 +15,6 @@
   "kiosk_enabled": true,
   "offline_enabled": true,
   "kiosk_secondary_apps": [
-    {"id": "imlgadjgphbjkaceoiapiephhgeofhic"}
+    {"id": "gdmgkkoghcihimdfoabkefdkccllcfea"}
   ]
 }
diff --git a/chrome/test/data/chromeos/app_mode/multi_app_kiosk/src/primary_app/v3/manifest.json b/chrome/test/data/chromeos/app_mode/multi_app_kiosk/src/primary_app/v3/manifest.json
index 0035ee3..adf341b5 100644
--- a/chrome/test/data/chromeos/app_mode/multi_app_kiosk/src/primary_app/v3/manifest.json
+++ b/chrome/test/data/chromeos/app_mode/multi_app_kiosk/src/primary_app/v3/manifest.json
@@ -15,9 +15,9 @@
   "kiosk_enabled": true,
   "offline_enabled": true,
   "kiosk_secondary_apps": [
-    {"id": "ihplaomghjbeafnpnjkhppmfpnmdihgd"},
-    {"id": "fiehokkcgaojmbhfhlpiheggjhaedjoc"},
-    {"id": "aabnpdpieclcikafhdkkpldcaodmfoai"}
+    {"id": "emnbflhfbllbehnpjmjddklbkeeoaaeg"},
+    {"id": "blmjgfbajihimkjmepbhgmjbopjchlda"},
+    {"id": "jkofhenkpndpdflehcjpcekgecjkpggg"}
   ],
   "permissions": [
     "power"
diff --git a/chrome/test/data/chromeos/app_mode/multi_app_kiosk/src/secondary_app_1/key.pem b/chrome/test/data/chromeos/app_mode/multi_app_kiosk/src/secondary_app_1/key.pem
new file mode 100644
index 0000000..9a6f7423
--- /dev/null
+++ b/chrome/test/data/chromeos/app_mode/multi_app_kiosk/src/secondary_app_1/key.pem
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDzgLk3sBpIZygk
+esyB/KqtrdK05IK4IK5JA3AWhRWMnJd5Go4u6F+TJldnP6eBA8gLrlqXgwLbFPI9
+0kPDjw+Lb/eydhN2icsVbAwBOrmce1S7B76Lh/PoAj3rqbGVudlIJTBuc/U9Zmkn
+renpOqgv6pAUGw5Fpo++6GH0wUGJmB41tdoI5OrkiR51nwbeqe8ZG2kOKMWJVGN0
+z0uxQ4iq8XJPghrh2FgdpUyB4asq5j/A2Z0QHAcCs73iAGES00KLLsUhuv/RvUjp
+M5YyK72RQk2G9JI1HnBoqwyI0oXiVr67AYzWw9Cw4PpObMBYWXMl7TF591DGFopp
+LmnweQRTAgMBAAECggEBAMmdQD5aojhmqTcjMedCxDMPpFHAjndUH9o2bX1H7eLB
+2S0djrJKFrBo45+Kde99qQn67+lZQWkSO8xyJ0dpUW6bY5Sw7UaNqsfu8TWnYP2u
+pCZDsEIpbAsiqBBTLcWR3tU8bZBWlKyk+dYvymgg+BbMeUUcbcG/um9QS6LyzIfV
+/V4LIq9Gf6WJJw0HB2muNCtzn1Bt55ZjGPK+QgGNYuteTNtcTLDPuEBTp8oQfBPw
+X6eDbTFL6EIEHqSWGLCg5QhtOvgz/3QTIeMzJYJ6n5zZZ+1nIZmGtk1wY4+aDpIe
+iQfjabak4fQ/hAnPSNMZvw8yjheWj4ENdCVzoCKOd2ECgYEA+7VW/wVGMIpiCW94
+TOXtoek74w74xz69OHcbLp3XzOvDtNfX5j7DORGOw/bukYp7qSH33/oui5mpQppD
+O5MVTk8/KFZtXvHY/5ffJzwGJdz3SCnZCoJyE0jME33pYlN6t10mEPBrh/35DcHv
+3vCqaLJN6F/lkQ8iIf/t1+7YxeMCgYEA96eRa/rJmnSH1zc8CNXK+quUHtokfv2W
+sc+x6VxSlKzpE6OU8Ay3TH94hoZfQRCsZMX1ab9nRfLwe8u9Bvi9jfwJkCJkr40b
+O/91JKAfXV3sxAwTMGW4ayBIa2ftjJfvm1ZYNs7QhwshcQ9OHqdnZWfaa93JkkZm
+BSUnAu4MktECgYEAt+Ogngk1YSsIOop0YgGs3RfvB5Adkjq0tLbXZfQs/2nS/aCe
++3go2d2I5oPVgQCiHUtSsxAsxxJIxP68VZ679w0QQCD8IFwhw4Epp5lDiI/pHJBu
+Hy5ztsD9TtQzGAGS6rkjoUZz2NNkC3f/DWnXpUt2fWjp51MeBabbFWFKfy8CgYB0
+CnxFUDluufN8kFD9AtAdLJA29JftOP2HS35djfjT2UFNBnUfFZY9rezXe9beMeXV
+Qjx/1EObrv2nxAtKXPrUsKf6dWMgLsn4DvbgtnZ71Sq/objMEJ2c9H96dDQGkJqg
++pBS/g0PedOtmjJMgrwb89GQgVeVxo6/Em15HfmeQQKBgQCBq/966gD0SZ9cHTw8
+7tRVrDEIAygjJYjCy3psHbBiorynbQAiBrnHfb2Ty3M4y7tygVHzGalrTwUYhe23
+0pQsMfwcJCZC03tq6ujQgUUKfNtD+NxCU7QixrTIVqUUlcuzBcv31cuZx1hekoje
+RJy//J+Smym4/T1gQNSpsqegiw==
+-----END PRIVATE KEY-----
diff --git a/chrome/test/data/chromeos/app_mode/multi_app_kiosk/src/secondary_app_2/key.pem b/chrome/test/data/chromeos/app_mode/multi_app_kiosk/src/secondary_app_2/key.pem
new file mode 100644
index 0000000..6ce94ca
--- /dev/null
+++ b/chrome/test/data/chromeos/app_mode/multi_app_kiosk/src/secondary_app_2/key.pem
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC7lD52iGwy/N8P
+AHbrUnI4fhOjmkXEPXAFW5xdnlIG+RS2TKUjqo5ufQwxBHeyWL/BmYtj4rekdke/
+jZ419EhTFwYUw6aLpLKQPTjeNylf4Zmr2xUchPaZSgSKemPZIrJY36QgBoXf+G+r
+99gMYMJAecyzPoWsCvb+W64D48XrOQHaRf3T7CQpiyVemdfB/TrP4Qmd2U3tLzB3
+HbSfEQ7AkDpupdv2sovyuR1SAxY8JkgLUoDtU46xUGwFS9hs8YhcY8gHs8V9Gqvx
+YPFxNCVP3v4Sz4FWRZvFzhrzTuE5c1JVDg2oXPSKLviXvw8aboRlkq1RlduTqQ7N
+llJPnSppAgMBAAECggEAfZe8WtDs4Ra+ouTEurrxDzIbJCdfHw2ju3KjN2uRsGmF
+nKmkyESiKQhA6XD8U8VoXs/XrIFYRB2N3IuNqsJsynVX9P8qu8UCaeET+nUklrYO
+liqR8A52rhwI/k8EG5ZHo4nZ8jdr25IT8yh215LRfSoQDNOH3LFavuPTl3ciRWM4
+ZFLkGO8QrfoDAdoC6xYNFDWGHLz5tvOtZ+p2iEZ7z1WYwebqmi7wgVnjQEUkDwg2
+j9XlpAxM4x2rK5Wv5L6M3QRm7ct2qpA3v7D7Xt7wwyH8bs1fa25BB32DzdpcqDBh
+k1wqzUOGsK9xDinuLCbNCkhEdzc1bZla/1jXF7EiIQKBgQDivV/JqNHk1kFw2jQz
+PCMjNfRp9mPGXSUdBIrK9G19HyffjgQLQmiP17yZ7JHL+X+fd0tMhpuwlrnEPYNp
+J24u6rwfHq/MHIz96I6/mRFMr9KFSc+LmG9IkdE/wxMG4Rl7fdAnliAOjt3cq/gv
+RfS2F9Tm6PgEHOPfa0xKuyGvVwKBgQDTySYwjWB6/YjNC2Ray/7SmxNxG7PwpZIa
+AegZfXoldK/baskKbpj8bjCer+4RV4kU/60YJyN9TtjY62Ol3U1LAFN8XyFaGDea
+Dx4dB3LkX+eCcRrCrUguNGqQif8GEAaEoNWkfNkiuZzNVovysmwfsdLI+opyBBo4
+J4F8ZhacPwKBgB5uhFiwi9tG1mmrH65wt9aV+0Ptid6pyb1nSqmKvNc6Q0PB79ED
+DL2hmvKdycOyrOpePID84BCHak9oYibO3/70CmOy3q1qd5HskJwukx/TyVGSYoS9
+5NG8oHUKXZdixuTIMhPeFldd3XEss5bEsN9vu2dyhTcoGX13DTpKe27pAoGABdvZ
+r5wpoB1lbG61PwHHseHSXt2qU6zw5sFIv3PGLkUVHFfO6ff3SXxu4eTyDA7E3wzX
+qARlKfFFdHLGle8SVVHT/WvQS2LCHwPuDFWJayHwEJ66Y8pRZd3TWN5IbM2CsKaW
+Ym+Fvj0uRkvvoS4oaZQMxbyQmejdJNKK9XsJgxcCgYEAtJmoe7hiCTqKetX7N56P
+uxOmf1KpRnqDgWyq+l8dTJ4rSPOGr8N1X7JGGoHaO/8ElWkPKJ2WNAB1HbRMFTNz
++3NhQLLEZUp64nLUtMSaN2XvQhSminbzPtLF+i0jijjfw4HYTb64kDAbFlz8zrJ3
+Oahu+bwAN5SyrQgIJI4BxDw=
+-----END PRIVATE KEY-----
diff --git a/chrome/test/data/chromeos/app_mode/multi_app_kiosk/src/secondary_app_3/key.pem b/chrome/test/data/chromeos/app_mode/multi_app_kiosk/src/secondary_app_3/key.pem
new file mode 100644
index 0000000..59503ea9
--- /dev/null
+++ b/chrome/test/data/chromeos/app_mode/multi_app_kiosk/src/secondary_app_3/key.pem
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQC4BIDw3iHLPtZ4
+LBEEeojs5z4DsBdpN1wwNsPSV8PP5otZORAeYeB6KY5CrXOtogoiNwZGm1CbX/2E
+2s4+qpN1ZmvuR49jKvYemNPPX5WO0mQHVRzJOU73V6FtSFvSnyj4oAnOSasuSGtb
+CebJjQxYv0mWeMMfK9AFr6zyN4KEntnHjKWcqAcuxNRkcjNeFL3mVGFku5eo9i8M
+XMffH8mwK4Jb4uH42ux9PJH/HMYC/n6Sn+gfEOGPh3/jKxUgPfCBkuoj58QqJ3Yt
+jyDUGi6ilVMa0754xTkpQUwIVsHzR/86BzA+3/j8z76vxYGyq0PfKXD4EfoajNBT
+poWFl1TBAgMBAAECggEBALJP4uYESXjZ5hbClKbjWeU92jDWpIjXFSS/HJepZdwC
+SUtm6QCX1V5rACgKTYqV9v3aleE7RSuaI15ma+37ejIL0lAt1XrBuYZCjxRmSdUA
+d99HEULHnoY8yvbLY/a/NYNeCMJ1TkPl9ulbud/aJnmkuljtoh2FZejsp0h6k6WP
+ZWEMmIdpSIMNktIjeBTmuQWoGibX04WpKqbdt9QhGz0sRoojjA8foLje39oEW7a1
+8E0VJibfXUm7GgzdzLmVJTiViBzf2+4ZUdfZOzksl/9/QjT4okdI4g984+aTddet
+gp37Nkf+m33ASCyFgKiU28Z0WSqS6nA/lT+M8X0pYwECgYEA7vOo1O3IfnS+xOz5
+6Z+PHADtOJRTozBqty/RqAfBp0nVVbnxpj8VHNxr/4kBrOaKvXMr0mMfKUTvrQEr
+tZX0PNVYvdzMvEdf3b5QEvnZBjC/2zQAxiSj2mqTMFcW488NluWGHFuGm2N1MdcO
+FzgiTrbSKC1+KEmBFaoIfPpOllECgYEAxSV/R352qMTmQkr+ImgP49pL6+lIVkLj
+FKE/UsWVGRcz14pxuOg9yaC2KCv0nAcFEPTMOL2mv1RVuKwVzeiFcNAOrook6oG9
+eTAup606HFzkDvLxRXpH4Oj8zqu5riI3Faw+ViCo5AiK54t58qKpzWBsFjVZ1cdQ
+gMpZhwF5i3ECgYEAobpvCfcKnXRc7iJKn/IrxVNnO8VAupH5mJUX/PeK/bP+XXBl
++xR1MLyLqD/Nz32WZ9V80n/eRmtvIRRKxjOBRG9OCetY8xIH86hsv/s1BXiXUkDn
+STThZeJ+TtiTGIs6cmhVFfpop+FwH9Sjp9mJdudMZH8uBQyC/uu/pP8xk5ECgYBt
+/Bdf+WuViBO1lETnSQrkYRrOCB11EmfBUJwVP2mIz+r6KqB7OgWOgPxeuPcEPN5U
+sV1lolhukUwpdMfNUhVv9ILcWPFzauIbxAejP/8VZ7VLqbl0u11yWkj/u8ohHbGB
+g9BbGGlgnmtv9d4YwSreCxcB5M2zeDivQTRlHyuB4QKBgQCmKoHvFapbJ6MgG1r8
+bFFdl6UXehN6q6KXS+T4jCUbbLJbyI6uj39QOB9BsbHB6qI30g0GfF6rq3Vrsx9n
+B3RxvyoZhnvXn1gCubvcl+wNPMKSYumDBOzvk+zQxXp3UMT9q8E6sfG9YmwajPu3
+Tid+7nx+zm42NvmzVDi3jgyutQ==
+-----END PRIVATE KEY-----
diff --git a/chrome/test/data/chromeos/app_mode/multi_app_kiosk/src/secondary_extension_1/key.pem b/chrome/test/data/chromeos/app_mode/multi_app_kiosk/src/secondary_extension_1/key.pem
new file mode 100644
index 0000000..8597665b
--- /dev/null
+++ b/chrome/test/data/chromeos/app_mode/multi_app_kiosk/src/secondary_extension_1/key.pem
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEuwIBADANBgkqhkiG9w0BAQEFAASCBKUwggShAgEAAoIBAQC5Yqr1sdfY5Kr8
+OPq1tj1M31P9ICSFOhR5FUMP6WQ3uPr4TV1wpenG/WtUl68S/HQ6gj8qu7Shcq+E
+AG8tJZ6ZgrV4I3NuFpq2xiI9OjCIDfHT+LpOohcagETtDTGVhJWwyEHUqC9rsQ0P
+BWxyogwBGIFIJRz8IwZ08e8ntrrgV7OuUmeK7pgjw0SI7may7FWdTOoLNhvAtZDh
+Q6TJOi2ZHRZ+ekAccQ1fUMCoeQoPmjtLb3faR+WV0hLb5JppEdtSl05j1X4LSGnr
+9+67J3ZBZN87DjMkPu+BOdpR2EKOgFwnGNkXVvqbQz7oIy7tv/Ctj9JU1ilfPwMn
+iioQhMOVAgMBAAECgf9EEfa0QJkBCvW9py5nioL3twkf6K2APdNGoof9T7V8wG9m
+vQGSW1l7t5GxfgDK9+e1lB2dk06/+Vx5G6+25BlYRKZddqbrxWEJu7bWxIcNbhFd
+w/ak6N+S24ZzhGSwgf506xNBAoBnCpvA6Dzp2paN0HGoC/iYnEPCrRMjgfUcaneS
+7LWVy38+niCGy7WKdv5GBS/nALVx5CXRqeawXs8Awa49mfV63P3s3dIE5COK55xw
+32SQVMuXCV9ZC2C+tbdFxKKAzgQVGS3oENa/ov3TP9FXlr0nlj9FAGigvhMl0qKB
+gjXXxCL5/xpkw+9ZdD9lmlV8LlKvyKCEM5Oc3IECgYEA2zbBWiJUksyKqAalaO7Z
+jgShtjRlGEv+gm2TxV2fGFoxDYK8s0Se/obyhCoDzRluRXS0u2wTZuYXRbFkL4PT
+JsUvlOaNmfRJ9lfuiFdX3E3sg0Uzulr+7XN7tdUz1szA+Ft+ESQ2N0HlHxGMDk97
+wb7Wfp9F5M4PmvFJAn5/lPECgYEA2H6rg9mchTustKBz7II85kQ013RBu22iYPF6
+KrcfLL1iANIfDJ8dB0A+P4dp6hQCsM/3Go+jLTLpM5u/zYL2pEKOGssQAlrEjBNe
+hNpYerxYpprfsq0g9NPfsxzpUNJd8IRnzymo/T3FZZWWO4okmY0Wp+Uuv3sbfS6N
+KBONCOUCgYEAgZMCAxcbypHgu6UCDN5x9gJC3AJoZ040KEBBAn5uVeSp7gSDKau8
+F1MI8porGQaZKbDsS4R8i2wiAW3zfCp9mwMfNvJ4bLH7LgOX2TtXkb71uDolc1fq
+K80BKN/W/naU8biS8ernqQ3oMs8abDMLQeBdxQa8N5ydmMZak4DWROECgYAL2/R9
+RoBidABj7J4tCH1Zh8b1PnMTV1Aby16L1HgqtT0XGmuE/3pRmV1PkZVlsy7qjJnW
+pKOlqDJKF3AMS+5C1Tp/kTwRRPObULxOvr82Cfc5OSaj3QP/JVQNtbm6KavnrvkY
+ygltxeJ4TBdsr4aNusLQ86b56j55PwGQfnGtWQKBgBvrYWZn9EY09HZGrmI5pK3P
+08roc7qjU6sRKQUdST1qWaPo/Ct8N1t0cx9IjOx29vRm6LjaF8SNMAW9wQUliJkK
+QCwO5RJGSh4H/ujUPVJaf7gWp/3hrsFvdFqLiweMbP21Us3j/drR0EdZK2Rt29hJ
+zLxK87gXUSzJKDND1XQ3
+-----END PRIVATE KEY-----
diff --git a/chrome/test/data/chromeos/app_mode/multi_app_kiosk/src/secondary_extension_1/manifest.json b/chrome/test/data/chromeos/app_mode/multi_app_kiosk/src/secondary_extension_1/manifest.json
index 93e183c..7a9aaf4 100644
--- a/chrome/test/data/chromeos/app_mode/multi_app_kiosk/src/secondary_extension_1/manifest.json
+++ b/chrome/test/data/chromeos/app_mode/multi_app_kiosk/src/secondary_extension_1/manifest.json
@@ -10,6 +10,5 @@
   "background": {
      "scripts": ["main.js"]
   },
-  "kiosk_enabled": true,
   "offline_enabled": true
 }
diff --git a/chrome/test/data/chromeos/app_mode/multi_app_kiosk/src/shared_module/v2/manifest.json b/chrome/test/data/chromeos/app_mode/multi_app_kiosk/src/shared_module/v2/manifest.json
new file mode 100644
index 0000000..f8f06db
--- /dev/null
+++ b/chrome/test/data/chromeos/app_mode/multi_app_kiosk/src/shared_module/v2/manifest.json
@@ -0,0 +1,6 @@
+{
+  "export": {},
+  "name": "Shared Module",
+  "manifest_version": 2,
+  "version": "2.0.0"
+}
diff --git a/chrome/test/data/chromeos/app_mode/multi_app_kiosk/src/shared_module/v2/pass.js b/chrome/test/data/chromeos/app_mode/multi_app_kiosk/src/shared_module/v2/pass.js
new file mode 100644
index 0000000..1e1d7e5
--- /dev/null
+++ b/chrome/test/data/chromeos/app_mode/multi_app_kiosk/src/shared_module/v2/pass.js
@@ -0,0 +1,5 @@
+// Copyright (c) 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.
+
+var pass_shared_module = {};
diff --git a/chrome/test/data/chromeos/app_mode/webstore/downloads/aabnpdpieclcikafhdkkpldcaodmfoai-1.0.0.crx b/chrome/test/data/chromeos/app_mode/webstore/downloads/aabnpdpieclcikafhdkkpldcaodmfoai-1.0.0.crx
deleted file mode 100644
index d77cb21..0000000
--- a/chrome/test/data/chromeos/app_mode/webstore/downloads/aabnpdpieclcikafhdkkpldcaodmfoai-1.0.0.crx
+++ /dev/null
Binary files differ
diff --git a/chrome/test/data/chromeos/app_mode/webstore/downloads/biebhpdepndljbnkadldcbjkiedldnmn-2.0.0.crx b/chrome/test/data/chromeos/app_mode/webstore/downloads/biebhpdepndljbnkadldcbjkiedldnmn-2.0.0.crx
new file mode 100644
index 0000000..cd4d9b4
--- /dev/null
+++ b/chrome/test/data/chromeos/app_mode/webstore/downloads/biebhpdepndljbnkadldcbjkiedldnmn-2.0.0.crx
Binary files differ
diff --git a/chrome/test/data/chromeos/app_mode/webstore/downloads/blmjgfbajihimkjmepbhgmjbopjchlda-1.0.0.crx b/chrome/test/data/chromeos/app_mode/webstore/downloads/blmjgfbajihimkjmepbhgmjbopjchlda-1.0.0.crx
new file mode 100644
index 0000000..85ccadde
--- /dev/null
+++ b/chrome/test/data/chromeos/app_mode/webstore/downloads/blmjgfbajihimkjmepbhgmjbopjchlda-1.0.0.crx
Binary files differ
diff --git a/chrome/test/data/chromeos/app_mode/webstore/downloads/ceobkcclegcliomogfoeoheahogoecgl-1.0.0.crx b/chrome/test/data/chromeos/app_mode/webstore/downloads/ceobkcclegcliomogfoeoheahogoecgl-1.0.0.crx
deleted file mode 100644
index cb5c5e0..0000000
--- a/chrome/test/data/chromeos/app_mode/webstore/downloads/ceobkcclegcliomogfoeoheahogoecgl-1.0.0.crx
+++ /dev/null
Binary files differ
diff --git a/chrome/test/data/chromeos/app_mode/webstore/downloads/ceobkcclegcliomogfoeoheahogoecgl-2.0.0-1app.crx b/chrome/test/data/chromeos/app_mode/webstore/downloads/ceobkcclegcliomogfoeoheahogoecgl-2.0.0-1app.crx
deleted file mode 100644
index a7e8657..0000000
--- a/chrome/test/data/chromeos/app_mode/webstore/downloads/ceobkcclegcliomogfoeoheahogoecgl-2.0.0-1app.crx
+++ /dev/null
Binary files differ
diff --git a/chrome/test/data/chromeos/app_mode/webstore/downloads/ceobkcclegcliomogfoeoheahogoecgl-24.0.0.crx b/chrome/test/data/chromeos/app_mode/webstore/downloads/ceobkcclegcliomogfoeoheahogoecgl-24.0.0.crx
deleted file mode 100644
index df8d87b..0000000
--- a/chrome/test/data/chromeos/app_mode/webstore/downloads/ceobkcclegcliomogfoeoheahogoecgl-24.0.0.crx
+++ /dev/null
Binary files differ
diff --git a/chrome/test/data/chromeos/app_mode/webstore/downloads/ceobkcclegcliomogfoeoheahogoecgl-3.0.0-3app.crx b/chrome/test/data/chromeos/app_mode/webstore/downloads/ceobkcclegcliomogfoeoheahogoecgl-3.0.0-3app.crx
deleted file mode 100644
index 8768f88..0000000
--- a/chrome/test/data/chromeos/app_mode/webstore/downloads/ceobkcclegcliomogfoeoheahogoecgl-3.0.0-3app.crx
+++ /dev/null
Binary files differ
diff --git a/chrome/test/data/chromeos/app_mode/webstore/downloads/dpejijbnadgcgmabkmcoajkgongfgnii-1.0.0.crx b/chrome/test/data/chromeos/app_mode/webstore/downloads/dpejijbnadgcgmabkmcoajkgongfgnii-1.0.0.crx
new file mode 100644
index 0000000..0a4d20a2
--- /dev/null
+++ b/chrome/test/data/chromeos/app_mode/webstore/downloads/dpejijbnadgcgmabkmcoajkgongfgnii-1.0.0.crx
Binary files differ
diff --git a/chrome/test/data/chromeos/app_mode/webstore/downloads/dpejijbnadgcgmabkmcoajkgongfgnii-2.0.0.crx b/chrome/test/data/chromeos/app_mode/webstore/downloads/dpejijbnadgcgmabkmcoajkgongfgnii-2.0.0.crx
new file mode 100644
index 0000000..86100eb
--- /dev/null
+++ b/chrome/test/data/chromeos/app_mode/webstore/downloads/dpejijbnadgcgmabkmcoajkgongfgnii-2.0.0.crx
Binary files differ
diff --git a/chrome/test/data/chromeos/app_mode/webstore/downloads/dpejijbnadgcgmabkmcoajkgongfgnii-24.0.0.crx b/chrome/test/data/chromeos/app_mode/webstore/downloads/dpejijbnadgcgmabkmcoajkgongfgnii-24.0.0.crx
new file mode 100644
index 0000000..21e9b17
--- /dev/null
+++ b/chrome/test/data/chromeos/app_mode/webstore/downloads/dpejijbnadgcgmabkmcoajkgongfgnii-24.0.0.crx
Binary files differ
diff --git a/chrome/test/data/chromeos/app_mode/webstore/downloads/dpejijbnadgcgmabkmcoajkgongfgnii-3.0.0.crx b/chrome/test/data/chromeos/app_mode/webstore/downloads/dpejijbnadgcgmabkmcoajkgongfgnii-3.0.0.crx
new file mode 100644
index 0000000..e6e689c1
--- /dev/null
+++ b/chrome/test/data/chromeos/app_mode/webstore/downloads/dpejijbnadgcgmabkmcoajkgongfgnii-3.0.0.crx
Binary files differ
diff --git a/chrome/test/data/chromeos/app_mode/webstore/downloads/emnbflhfbllbehnpjmjddklbkeeoaaeg-1.0.0.crx b/chrome/test/data/chromeos/app_mode/webstore/downloads/emnbflhfbllbehnpjmjddklbkeeoaaeg-1.0.0.crx
new file mode 100644
index 0000000..72414cd
--- /dev/null
+++ b/chrome/test/data/chromeos/app_mode/webstore/downloads/emnbflhfbllbehnpjmjddklbkeeoaaeg-1.0.0.crx
Binary files differ
diff --git a/chrome/test/data/chromeos/app_mode/webstore/downloads/fiehokkcgaojmbhfhlpiheggjhaedjoc-1.0.0.crx b/chrome/test/data/chromeos/app_mode/webstore/downloads/fiehokkcgaojmbhfhlpiheggjhaedjoc-1.0.0.crx
deleted file mode 100644
index 4b90489..0000000
--- a/chrome/test/data/chromeos/app_mode/webstore/downloads/fiehokkcgaojmbhfhlpiheggjhaedjoc-1.0.0.crx
+++ /dev/null
Binary files differ
diff --git a/chrome/test/data/chromeos/app_mode/webstore/downloads/gdmgkkoghcihimdfoabkefdkccllcfea-1.0.0.crx b/chrome/test/data/chromeos/app_mode/webstore/downloads/gdmgkkoghcihimdfoabkefdkccllcfea-1.0.0.crx
new file mode 100644
index 0000000..900823bb
--- /dev/null
+++ b/chrome/test/data/chromeos/app_mode/webstore/downloads/gdmgkkoghcihimdfoabkefdkccllcfea-1.0.0.crx
Binary files differ
diff --git a/chrome/test/data/chromeos/app_mode/webstore/downloads/ihplaomghjbeafnpnjkhppmfpnmdihgd-1.0.0.crx b/chrome/test/data/chromeos/app_mode/webstore/downloads/ihplaomghjbeafnpnjkhppmfpnmdihgd-1.0.0.crx
deleted file mode 100644
index 734efcc..0000000
--- a/chrome/test/data/chromeos/app_mode/webstore/downloads/ihplaomghjbeafnpnjkhppmfpnmdihgd-1.0.0.crx
+++ /dev/null
Binary files differ
diff --git a/chrome/test/data/chromeos/app_mode/webstore/downloads/imlgadjgphbjkaceoiapiephhgeofhic-1.0.0.crx b/chrome/test/data/chromeos/app_mode/webstore/downloads/imlgadjgphbjkaceoiapiephhgeofhic-1.0.0.crx
deleted file mode 100644
index 23d0e6a3..0000000
--- a/chrome/test/data/chromeos/app_mode/webstore/downloads/imlgadjgphbjkaceoiapiephhgeofhic-1.0.0.crx
+++ /dev/null
Binary files differ
diff --git a/chrome/test/data/chromeos/app_mode/webstore/downloads/jkofhenkpndpdflehcjpcekgecjkpggg-1.0.0.crx b/chrome/test/data/chromeos/app_mode/webstore/downloads/jkofhenkpndpdflehcjpcekgecjkpggg-1.0.0.crx
new file mode 100644
index 0000000..963703f
--- /dev/null
+++ b/chrome/test/data/chromeos/app_mode/webstore/downloads/jkofhenkpndpdflehcjpcekgecjkpggg-1.0.0.crx
Binary files differ
diff --git a/chrome/test/data/extensions/platform_apps/web_view/shim/main.js b/chrome/test/data/extensions/platform_apps/web_view/shim/main.js
index 553b54d2..9cc1005b 100644
--- a/chrome/test/data/extensions/platform_apps/web_view/shim/main.js
+++ b/chrome/test/data/extensions/platform_apps/web_view/shim/main.js
@@ -1298,6 +1298,55 @@
   document.body.appendChild(webview);
 }
 
+// This test verifies that, in the case where the WebView is set up with a
+// 'loadabort' handler that calls executeScript() with a script that sets
+// the WebView's 'src' to an invalid URL, and the caller then calls
+// executeScript() on that WebView with that same script (that sets 'src'
+// to an invalid URL), that loadabort will get called in both cases (and
+// that the browser does not crash during the second call to executeScript()).
+function testExecuteScriptIsAbortedWhenWebViewSourceIsInvalid() {
+  var webview = document.createElement('webview');
+  var abortCount = 0;
+
+  webview.addEventListener('loadstop', loadDone);
+  webview.addEventListener('loadabort', loadAbort);
+  webview.addEventListener('exit', function(e) {
+    // We should not crash.
+    embedder.test.fail();
+  });
+
+  function loadDone() {
+    window.console.log(
+        '2. WebView loaded \'about:blank\'.  Now call \'executeScript()\'');
+    webview.executeScript( {code: '/* no op */'}, webviewStop);
+  }
+
+  function webviewStop() {
+    window.console.log(
+        '3. Executing the script.  Set webview.src to ' +
+        '\'http:\' (which is invalid and should cause an abort)');
+    webview.src = 'http:';
+  }
+
+  function loadAbort() {
+    abortCount++;
+    if (abortCount == 1) {
+      window.console.log(
+          '4. In \'loadabort\' handler.  Execute the script again, ' +
+          'which should cause the \'loadabort\' handler to be called again ' +
+          '(the browser should NOT crash)');
+      webview.executeScript( {code: '/* no op */'}, webviewStop);
+    } else {
+      window.console.log('5. In \'loadabort\' handler for 2nd time. Success!!');
+      embedder.test.succeed();
+    }
+  }
+
+  window.console.log('1. Set webview.src to \'about:blank\'');
+  webview.src = 'about:blank';
+  document.body.appendChild(webview);
+}
+
 // This test calls terminate() on guest after it has already been
 // terminated. This makes sure we ignore the call gracefully.
 function testTerminateAfterExit() {
@@ -2951,6 +3000,8 @@
   'testExecuteScript': testExecuteScript,
   'testExecuteScriptIsAbortedWhenWebViewSourceIsChanged':
       testExecuteScriptIsAbortedWhenWebViewSourceIsChanged,
+  'testExecuteScriptIsAbortedWhenWebViewSourceIsInvalid':
+      testExecuteScriptIsAbortedWhenWebViewSourceIsInvalid,
   'testTerminateAfterExit': testTerminateAfterExit,
   'testAssignSrcAfterCrash': testAssignSrcAfterCrash,
   'testNavOnConsecutiveSrcAttributeChanges':
diff --git a/chrome/test/data/password/password_autocomplete_off_test.html b/chrome/test/data/password/password_autocomplete_off_test.html
index 902409ad..ae18625 100644
--- a/chrome/test/data/password/password_autocomplete_off_test.html
+++ b/chrome/test/data/password/password_autocomplete_off_test.html
@@ -5,15 +5,10 @@
     <title>Password Test Form</title>
   </head>
   <body>
-    <form id="loginform" action="google.com" method="post">
-    <table cellspacing="3" cellpadding="5" border="0">
-      <tbody>
-        <tr><td>Username:</td><td align="left"><input type="text" name="Email" id="Email" size="18" value=""></td></tr>
-        <tr><td>Password:</td><td align="left"><input autocomplete="off" type="password" name="Passwd" id="Passwd" size="18"></td></tr>
-        <tr><td></td><td align="left"><input type="submit" class="button" name="signIn" id="signIn" value="Sign in"></td></tr>
-      </tbody>
-    </table>
+    <form method="POST" action="done.html" id="loginform">
+      <input type="text" id="username" autocomplete="off">
+      <input type="password" id="password" autocomplete="off">
+      <input type="submit" id="submit">
     </form>
   </body>
-</html>
-
+</html>
\ No newline at end of file
diff --git a/chrome/test/data/safe_browsing/malware2.html b/chrome/test/data/safe_browsing/malware2.html
new file mode 100644
index 0000000..27e22fd
--- /dev/null
+++ b/chrome/test/data/safe_browsing/malware2.html
@@ -0,0 +1,8 @@
+<html>
+<body>
+<iframe src="malware_iframe.html"></iframe>
+<iframe src="http://example.com/cross_site_iframe.html"></iframe>
+<img src="malware_image.png">
+<img src="http://example.com/image.png">
+</body>
+</html>
diff --git a/chrome/test/data/webui/extensions/extension_item_test.js b/chrome/test/data/webui/extensions/extension_item_test.js
index 2226972..d3b4f3ed 100644
--- a/chrome/test/data/webui/extensions/extension_item_test.js
+++ b/chrome/test/data/webui/extensions/extension_item_test.js
@@ -137,7 +137,9 @@
       setup(function() {
         PolymerTest.clearBody();
         mockDelegate = new MockDelegate();
-        item = new extensions.Item(extensionData, mockDelegate);
+        item = new extensions.Item();
+        item.set('data', extensionData);
+        item.set('delegate', mockDelegate);
         document.body.appendChild(item);
       });
 
diff --git a/chrome/test/data/webui/extensions/extension_manager_test.js b/chrome/test/data/webui/extensions/extension_manager_test.js
index aadf325d..06732593 100644
--- a/chrome/test/data/webui/extensions/extension_manager_test.js
+++ b/chrome/test/data/webui/extensions/extension_manager_test.js
@@ -20,82 +20,62 @@
       });
 
       test(assert(TestNames.SplitSections), function() {
-        var testVisible = extension_test_util.testVisible.bind(null, manager);
-        // All sections and headers should be visible.
-        testVisible('#extensions-header', true);
-        testVisible('#extensions-list', true);
-        testVisible('#apps-header', true);
-        testVisible('#apps-list', true);
-        testVisible('#websites-header', true);
-        testVisible('#websites-list', true);
+        var testManagerElementVisible =
+            extension_test_util.testVisible.bind(null, manager);
+        // All sections should be visible.
+        testManagerElementVisible('#extensions-list', true);
+        testManagerElementVisible('#apps-list', true);
+        testManagerElementVisible('#websites-list', true);
 
-        var findItemWithName = function(name) {
-          var result;
-          manager.forEachItem(function(item) {
-            if (item.data.name == name) {
-              expectFalse(!!result,
-                          'Found two items with the same name: ' + name);
-              result = item;
-            }
+        var sectionHasItemWithName = function(section, name) {
+          return !!manager[section].find(function(el) {
+            return el.name == name;
           });
-          expectTrue(!!result);
-          return result;
         };
 
-        // Find each type of extension. Each should be present, visible, and
-        // sorted in the correct section.
-        var extension = findItemWithName('My extension 1');
-        var selector = '#' + extension.data.id;
-        testVisible(selector, true)
-        expectTrue(!!manager.$$('#extensions-list').querySelector(selector));
+        expectEquals(manager.extensions, manager.$['extensions-list'].items);
+        expectEquals(manager.apps, manager.$['apps-list'].items);
+        expectEquals(manager.websites, manager.$['websites-list'].items);
 
-        var platform_app =
-            findItemWithName('Platform App Test: minimal platform app');
-        selector = '#' + platform_app.data.id
-        testVisible(selector, true)
-        expectTrue(!!manager.$$('#apps-list').querySelector(selector));
-
-        var hosted_app = findItemWithName('hosted_app');
-        selector = '#' + hosted_app.data.id;
-        testVisible(selector, true)
-        expectTrue(!!manager.$$('#websites-list').querySelector(selector));
-
-        var packaged_app = findItemWithName('Packaged App Test');
-        selector = '#' + packaged_app.data.id;
-        testVisible(selector, true)
-        expectTrue(!!manager.$$('#websites-list').querySelector(selector));
+        // We really just have to test for existence of the items within the
+        // given subsection of the manager, since they are bound to the iron
+        // list with Polymer (and we kind of have to trust that Polymer works).
+        expectTrue(sectionHasItemWithName('extensions', 'My extension 1'));
+        expectTrue(sectionHasItemWithName(
+            'apps', 'Platform App Test: minimal platform app'));
+        expectTrue(sectionHasItemWithName('websites', 'hosted_app'));
+        expectTrue(sectionHasItemWithName('websites', 'Packaged App Test'));
       });
 
       test(assert(TestNames.ItemOrder), function() {
-        var extensionsSection = manager.$['extensions-list'];
         var service = extensions.Service.getInstance();
-        expectEquals(0, extensionsSection.children.length);
+        expectEquals(0, manager.extensions.length);
 
         var alphaFromStore = extension_test_util.createExtensionInfo(
             {location: 'FROM_STORE', name: 'Alpha', id: 'a'.repeat(32)});
         manager.addItem(alphaFromStore, service);
 
-        expectEquals(1, extensionsSection.children.length);
-        expectEquals(alphaFromStore.id, extensionsSection.children[0].id);
+        expectEquals(1, manager.extensions.length);
+        expectEquals(alphaFromStore.id, manager.extensions[0].id);
 
         // Unpacked extensions come first.
         var betaUnpacked = extension_test_util.createExtensionInfo(
             {location: 'UNPACKED', name: 'Beta', id: 'b'.repeat(32)});
         manager.addItem(betaUnpacked, service);
 
-        expectEquals(2, extensionsSection.children.length);
-        expectEquals(betaUnpacked.id, extensionsSection.children[0].id);
-        expectEquals(alphaFromStore.id, extensionsSection.children[1].id);
+        expectEquals(2, manager.extensions.length);
+        expectEquals(betaUnpacked.id, manager.extensions[0].id);
+        expectEquals(alphaFromStore.id, manager.extensions[1].id);
 
         // Extensions from the same location are sorted by name.
         var gammaUnpacked = extension_test_util.createExtensionInfo(
             {location: 'UNPACKED', name: 'Gamma', id: 'c'.repeat(32)});
         manager.addItem(gammaUnpacked, service);
 
-        expectEquals(3, extensionsSection.children.length);
-        expectEquals(betaUnpacked.id, extensionsSection.children[0].id);
-        expectEquals(gammaUnpacked.id, extensionsSection.children[1].id);
-        expectEquals(alphaFromStore.id, extensionsSection.children[2].id);
+        expectEquals(3, manager.extensions.length);
+        expectEquals(betaUnpacked.id, manager.extensions[0].id);
+        expectEquals(gammaUnpacked.id, manager.extensions[1].id);
+        expectEquals(alphaFromStore.id, manager.extensions[2].id);
 
         // The name-sort should be case-insensitive, and should fall back on
         // id.
@@ -109,13 +89,13 @@
         manager.addItem(AaFromStore, service);
         manager.addItem(aAFromStore, service);
 
-        expectEquals(6, extensionsSection.children.length);
-        expectEquals(betaUnpacked.id, extensionsSection.children[0].id);
-        expectEquals(gammaUnpacked.id, extensionsSection.children[1].id);
-        expectEquals(aaFromStore.id, extensionsSection.children[2].id);
-        expectEquals(AaFromStore.id, extensionsSection.children[3].id);
-        expectEquals(aAFromStore.id, extensionsSection.children[4].id);
-        expectEquals(alphaFromStore.id, extensionsSection.children[5].id);
+        expectEquals(6, manager.extensions.length);
+        expectEquals(betaUnpacked.id, manager.extensions[0].id);
+        expectEquals(gammaUnpacked.id, manager.extensions[1].id);
+        expectEquals(aaFromStore.id, manager.extensions[2].id);
+        expectEquals(AaFromStore.id, manager.extensions[3].id);
+        expectEquals(aAFromStore.id, manager.extensions[4].id);
+        expectEquals(alphaFromStore.id, manager.extensions[5].id);
       });
     });
   }
diff --git a/chrome/test/data/webui/extensions/extension_service_test.js b/chrome/test/data/webui/extensions/extension_service_test.js
index db2a867..a578c07 100644
--- a/chrome/test/data/webui/extensions/extension_service_test.js
+++ b/chrome/test/data/webui/extensions/extension_service_test.js
@@ -83,6 +83,13 @@
       /** @type {extensions.Manager} */
       var manager;
 
+      var getItemData = function(id) {
+        var elMatches = function(el) { return el.id == id; };
+        return manager.extensions.find(elMatches) ||
+               manager.apps.find(elMatches) ||
+               manager.websites.find(elMatches);
+      };
+
       suiteSetup(function() {
         return PolymerTest.importHtml('chrome://extensions/service.html');
       });
@@ -94,33 +101,39 @@
       });
 
       test(assert(TestNames.EnableAndDisable), function(done) {
-        var item = manager.getItem(kExtensionId);
+        var item = getItemData(kExtensionId);
         assertTrue(!!item);
         expectEquals(kExtensionId, item.id);
-        expectEquals('My extension 1', item.data.name);
-        expectEquals(ExtensionState.ENABLED, item.data.state);
+        expectEquals('My extension 1', item.name);
+        expectEquals(ExtensionState.ENABLED, item.state);
 
         var disabledListener =
             new ItemChangedListener(kExtensionId, EventType.UNLOADED);
         service.setItemEnabled(kExtensionId, false);
         disabledListener.onUpdate.then(function() {
-          expectEquals(ExtensionState.DISABLED, item.data.state);
+          // Note: we need to re-get the item since the object in the manager's
+          // collection was replaced, rather than updated.
+          var item = getItemData(kExtensionId);
+          assertTrue(!!item);
+          expectEquals(ExtensionState.DISABLED, item.state);
 
           enabledListener =
               new ItemChangedListener(kExtensionId, EventType.LOADED);
           service.setItemEnabled(kExtensionId, true);
           return enabledListener.onUpdate;
         }).then(function() {
-          expectEquals(ExtensionState.ENABLED, item.data.state);
+          var item = getItemData(kExtensionId);
+          assertTrue(!!item);
+          expectEquals(ExtensionState.ENABLED, item.state);
           done();
         });
       });
 
       test(assert(TestNames.ToggleIncognitoMode), function(done) {
-        var item = manager.getItem(kExtensionId);
+        var item = getItemData(kExtensionId);
         assertTrue(!!item);
-        expectTrue(item.data.incognitoAccess.isEnabled);
-        expectFalse(item.data.incognitoAccess.isActive);
+        expectTrue(item.incognitoAccess.isEnabled);
+        expectFalse(item.incognitoAccess.isActive);
 
         var incognitoListener =
             new ItemChangedListener(kExtensionId, EventType.LOADED);
@@ -128,7 +141,9 @@
           service.setItemAllowedIncognito(kExtensionId, true);
         });
         incognitoListener.onUpdate.then(function() {
-          expectTrue(item.data.incognitoAccess.isActive);
+          var item = getItemData(kExtensionId);
+          assertTrue(!!item);
+          expectTrue(item.incognitoAccess.isActive);
 
           var disabledIncognitoListener =
               new ItemChangedListener(kExtensionId, EventType.LOADED);
@@ -137,13 +152,15 @@
           });
           return disabledIncognitoListener.onUpdate;
         }).then(function() {
-          expectFalse(item.data.incognitoAccess.isActive);
+          var item = getItemData(kExtensionId);
+          assertTrue(!!item);
+          expectFalse(item.incognitoAccess.isActive);
           done();
         });
       });
 
       test(assert(TestNames.Uninstall), function(done) {
-        var item = manager.getItem(kExtensionId);
+        var item = getItemData(kExtensionId);
         assertTrue(!!item);
         var uninstallListener =
             new ItemChangedListener(kExtensionId, EventType.UNINSTALLED);
@@ -151,27 +168,25 @@
           service.deleteItem(kExtensionId);
         });
         uninstallListener.onUpdate.then(function() {
-          expectFalse(!!manager.getItem(kExtensionId));
+          expectFalse(!!getItemData(kExtensionId));
           done();
         });
       });
 
       test(assert(TestNames.ProfileSettings), function(done) {
-        var item = manager.getItem(kExtensionId);
-        assertTrue(!!item);
-        expectFalse(item.inDevMode);
+        expectFalse(manager.inDevMode);
 
         var profileListener = new ProfileChangedListener();
         service.setProfileInDevMode(true);
 
         profileListener.onUpdate.then(function() {
-          expectTrue(item.inDevMode);
+          expectTrue(manager.inDevMode);
 
           var noDevModeProfileListener = new ProfileChangedListener();
           service.setProfileInDevMode(false);
           return noDevModeProfileListener.onUpdate;
         }).then(function() {
-          expectFalse(item.inDevMode);
+          expectFalse(manager.inDevMode);
           done();
         });
       });
diff --git a/chrome/test/data/webui/media_router/media_router_container_tests.js b/chrome/test/data/webui/media_router/media_router_container_tests.js
index ccdb963..abffbc9 100644
--- a/chrome/test/data/webui/media_router/media_router_container_tests.js
+++ b/chrome/test/data/webui/media_router/media_router_container_tests.js
@@ -88,11 +88,6 @@
         assertEquals(visible, elementVisible);
       };
 
-      // Checks whether |element| is hidden.
-      var checkElementHidden = function(hidden, element) {
-        assertEquals(hidden, element.hidden);
-      };
-
       // Checks whether |expected| and the text in the |element| are equal.
       var checkElementText = function(expected, element) {
         assertEquals(expected.trim(), element.textContent.trim());
@@ -142,13 +137,13 @@
         // Note: These need to be in-order by name to prevent shuffling.
         // Sorting of sinks by name is tested separately.
         fakeSinkList = [
-          new media_router.Sink('sink id 1', 'Sink 1',
+          new media_router.Sink('sink id 1', 'Sink 1', null,
               media_router.SinkIconType.CAST,
               media_router.SinkStatus.ACTIVE, [1, 2, 3]),
-          new media_router.Sink('sink id 2', 'Sink 2',
+          new media_router.Sink('sink id 2', 'Sink 2', null,
               media_router.SinkIconType.CAST,
               media_router.SinkStatus.ACTIVE, [1, 2, 3]),
-          new media_router.Sink('sink id 3', 'Sink 3',
+          new media_router.Sink('sink id 3', 'Sink 3', null,
               media_router.SinkIconType.CAST,
               media_router.SinkStatus.PENDING, [1, 2, 3]),
         ];
@@ -313,32 +308,47 @@
 
       // Tests the text shown for the sink list.
       test('initial sink list route text', function(done) {
-        container.allSinks = fakeSinkList;
-        container.routeList = fakeRouteList;
+        // Sink 1 - no sink description, no route -> no subtext
+        // Sink 2 - sink description, no route -> subtext = sink description
+        // Sink 3 - no sink description, route -> subtext = route description
+        // Sink 4 - sink description, route -> subtext = route description
+        container.allSinks = [
+            new media_router.Sink('sink id 1', 'Sink 1', null,
+                media_router.SinkIconType.CAST,
+                media_router.SinkStatus.ACTIVE, [1, 2, 3]),
+            new media_router.Sink('sink id 2', 'Sink 2', 'Sink 2 description',
+                media_router.SinkIconType.CAST,
+                media_router.SinkStatus.ACTIVE, [1, 2, 3]),
+            new media_router.Sink('sink id 3', 'Sink 3', null,
+                media_router.SinkIconType.CAST,
+                media_router.SinkStatus.PENDING, [1, 2, 3]),
+            new media_router.Sink('sink id 4', 'Sink 4', 'Sink 4 description',
+                media_router.SinkIconType.CAST,
+                media_router.SinkStatus.PENDING, [1, 2, 3])
+        ];
+
+        container.routeList = [
+            new media_router.Route('id 3', 'sink id 3', 'Title 3', 0, true),
+            new media_router.Route('id 4', 'sink id 4', 'Title 4', 1, false),
+        ];
 
         setTimeout(function() {
-          var routeList =
-              container.$['sink-list'].querySelectorAll('.route');
-          assertEquals(fakeSinkList.length, routeList.length);
-          checkElementText(fakeRouteList[0].description, routeList[0]);
-          checkElementText(fakeRouteList[1].description, routeList[1]);
-          checkElementText('', routeList[2]);
-          done();
-        });
-      });
+          var sinkSubtextList =
+              container.$['sink-list'].querySelectorAll('.sink-subtext');
 
-      // Tests the visibility of routes in the sink list.
-      test('initial route visibility', function(done) {
-        container.allSinks = fakeSinkList;
-        container.routeList = fakeRouteList;
+          // There will only be 3 sink subtext entries, because Sink 1 does not
+          // have any subtext.
+          assertEquals(3, sinkSubtextList.length);
 
-        setTimeout(function() {
-          var routeList =
-              container.$['sink-list'].querySelectorAll('.route');
+          checkElementText(container.allSinks[1].description,
+              sinkSubtextList[0]);
 
-          checkElementHidden(false, routeList[0]);
-          checkElementHidden(false, routeList[1]);
-          checkElementHidden(true, routeList[2]);
+          // Route description overrides sink description for subtext.
+          checkElementText(container.routeList[0].description,
+              sinkSubtextList[1]);
+
+          checkElementText(container.routeList[1].description,
+              sinkSubtextList[2]);
           done();
         });
       });
@@ -498,13 +508,13 @@
       // route.
       test('sink list filtering based on initial cast mode', function(done) {
         var newSinks = [
-          new media_router.Sink('sink id 10', 'Sink 10',
+          new media_router.Sink('sink id 10', 'Sink 10', null,
               media_router.SinkIconType.CAST,
               media_router.SinkStatus.ACTIVE, [2, 3]),
-          new media_router.Sink('sink id 20', 'Sink 20',
+          new media_router.Sink('sink id 20', 'Sink 20', null,
               media_router.SinkIconType.CAST,
               media_router.SinkStatus.ACTIVE, [1, 2, 3]),
-          new media_router.Sink('sink id 30', 'Sink 30',
+          new media_router.Sink('sink id 30', 'Sink 30', null,
               media_router.SinkIconType.CAST,
               media_router.SinkStatus.PENDING, [2, 3]),
         ];
@@ -568,22 +578,22 @@
       // when shown to the user.
       test('sinks are shown sorted by name', function(done) {
         var outOfOrderSinks = [
-          new media_router.Sink('6543', 'Sleepy',
+          new media_router.Sink('6543', 'Sleepy', null,
               media_router.SinkIconType.CAST,
               media_router.SinkStatus.ACTIVE, [1]),
-          new media_router.Sink('543', 'Happy',
+          new media_router.Sink('543', 'Happy', null,
               media_router.SinkIconType.CAST,
               media_router.SinkStatus.ACTIVE, [1]),
-          new media_router.Sink('43', 'Bashful',
+          new media_router.Sink('43', 'Bashful', null,
               media_router.SinkIconType.CAST,
               media_router.SinkStatus.ACTIVE, [1]),
-          new media_router.Sink('2', 'George',
+          new media_router.Sink('2', 'George', null,
               media_router.SinkIconType.CAST_AUDIO,
               media_router.SinkStatus.ACTIVE, [1]),
-          new media_router.Sink('1', 'George',
+          new media_router.Sink('1', 'George', null,
               media_router.SinkIconType.CAST,
               media_router.SinkStatus.ACTIVE, [1]),
-          new media_router.Sink('3', 'George',
+          new media_router.Sink('3', 'George', null,
               media_router.SinkIconType.HANGOUT,
               media_router.SinkStatus.ACTIVE, [1]),
         ];
diff --git a/chrome/test/data/webui/settings/reset_page_test.js b/chrome/test/data/webui/settings/reset_page_test.js
index d1a0695c..d2576638 100644
--- a/chrome/test/data/webui/settings/reset_page_test.js
+++ b/chrome/test/data/webui/settings/reset_page_test.js
@@ -41,9 +41,13 @@
         document.body.appendChild(resetPage);
       });
 
-      // Tests that the reset profile dialog opens and closes correctly, and
-      // that chrome.send calls are propagated as expected.
-      test(TestNames.ResetProfileDialogOpenClose, function() {
+
+      /**
+       * @param {string} closeButtonId The ID of the button that closes the
+       *     dialog.
+       * @return {!Promise}
+       */
+      function testOpenCloseResetProfileDialog(closeButtonId) {
         var onShowResetProfileDialogCalled = whenChromeSendCalled(
             'onShowResetProfileDialog');
         var onHideResetProfileDialogCalled = whenChromeSendCalled(
@@ -57,13 +61,24 @@
               dialog.addEventListener('iron-overlay-closed', resolve);
             });
 
-        MockInteractions.tap(dialog.$.cancel);
+        MockInteractions.tap(dialog.$[closeButtonId]);
 
         return Promise.all([
           onShowResetProfileDialogCalled,
           onHideResetProfileDialogCalled,
           onDialogClosed
         ]);
+      }
+
+      // Tests that the reset profile dialog opens and closes correctly and that
+      // chrome.send calls are propagated as expected.
+      test(TestNames.ResetProfileDialogOpenClose, function() {
+        return Promise.all([
+          // Test case where the 'cancel' button is clicked.
+          testOpenCloseResetProfileDialog('cancel'),
+          // Test case where the 'close' button is clicked.
+          testOpenCloseResetProfileDialog('close')
+        ]);
       });
 
       // Tests that when resetting the profile is requested chrome.send calls
@@ -78,9 +93,12 @@
       });
 
       if (cr.isChromeOS) {
-        // Tests that the powerwash dialog opens and closes correctly, and
-        // that chrome.send calls are propagated as expected.
-        test(TestNames.PowerwashDialogOpenClose, function() {
+        /**
+         * @param {string} closeButtonId The ID of the button that closes the
+         *     dialog.
+         * @return {!Promise}
+         */
+        function testOpenClosePowerwashDialog(closeButtonId) {
           var onPowerwashDialogShowCalled = whenChromeSendCalled(
               'onPowerwashDialogShow');
 
@@ -92,8 +110,19 @@
                 dialog.addEventListener('iron-overlay-closed', resolve);
               });
 
-          MockInteractions.tap(dialog.$.cancel);
+          MockInteractions.tap(dialog.$[closeButtonId]);
           return Promise.all([onPowerwashDialogShowCalled, onDialogClosed]);
+        }
+
+        // Tests that the powerwash dialog opens and closes correctly, and
+        // that chrome.send calls are propagated as expected.
+        test(TestNames.PowerwashDialogOpenClose, function() {
+          return Promise.all([
+            // Test case where the 'cancel' button is clicked.
+            testOpenClosePowerwashDialog('cancel'),
+            // Test case where the 'close' button is clicked.
+            testOpenClosePowerwashDialog('close')
+          ]);
         });
 
         // Tests that when powerwash is requested chrome.send calls are
diff --git a/chrome/utility/importer/importer_creator.cc b/chrome/utility/importer/importer_creator.cc
index f260f8c5..48c7c0c 100644
--- a/chrome/utility/importer/importer_creator.cc
+++ b/chrome/utility/importer/importer_creator.cc
@@ -23,7 +23,7 @@
 
 namespace importer {
 
-Importer* CreateImporterByType(ImporterType type) {
+scoped_refptr<Importer> CreateImporterByType(ImporterType type) {
   switch (type) {
 #if defined(OS_WIN)
     case TYPE_IE:
@@ -44,7 +44,7 @@
 #endif
     default:
       NOTREACHED();
-      return NULL;
+      return nullptr;
   }
 }
 
diff --git a/chrome/utility/importer/importer_creator.h b/chrome/utility/importer/importer_creator.h
index 40e0de5..dc61cd1 100644
--- a/chrome/utility/importer/importer_creator.h
+++ b/chrome/utility/importer/importer_creator.h
@@ -5,6 +5,7 @@
 #ifndef CHROME_UTILITY_IMPORTER_IMPORTER_CREATOR_H_
 #define CHROME_UTILITY_IMPORTER_IMPORTER_CREATOR_H_
 
+#include "base/memory/ref_counted.h"
 #include "chrome/common/importer/importer_type.h"
 
 class Importer;
@@ -12,7 +13,7 @@
 namespace importer {
 
 // Creates an Importer of the specified |type|.
-Importer* CreateImporterByType(ImporterType type);
+scoped_refptr<Importer> CreateImporterByType(ImporterType type);
 
 }  // namespace importer
 
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM
index b98d630..8d7cfda 100644
--- a/chromeos/CHROMEOS_LKGM
+++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@
-7692.0.0
\ No newline at end of file
+7703.0.0
\ No newline at end of file
diff --git a/chromeos/dbus/power_policy_controller.cc b/chromeos/dbus/power_policy_controller.cc
index e934275..336b72e 100644
--- a/chromeos/dbus/power_policy_controller.cc
+++ b/chromeos/dbus/power_policy_controller.cc
@@ -246,6 +246,11 @@
   return AddWakeLockInternal(WakeLock::TYPE_SCREEN, reason, description);
 }
 
+int PowerPolicyController::AddDimWakeLock(WakeLockReason reason,
+                                          const std::string& description) {
+  return AddWakeLockInternal(WakeLock::TYPE_DIM, reason, description);
+}
+
 int PowerPolicyController::AddSystemWakeLock(WakeLockReason reason,
                                              const std::string& description) {
   return AddWakeLockInternal(WakeLock::TYPE_SYSTEM, reason, description);
@@ -301,6 +306,7 @@
     causes = kPrefsReason;
 
   bool have_screen_wake_locks = false;
+  bool have_dim_wake_locks = false;
   bool have_system_wake_locks = false;
   for (const auto& it : wake_locks_) {
     // Skip audio and video locks that should be ignored due to policy.
@@ -312,6 +318,9 @@
       case WakeLock::TYPE_SCREEN:
         have_screen_wake_locks = true;
         break;
+      case WakeLock::TYPE_DIM:
+        have_dim_wake_locks = true;
+        break;
       case WakeLock::TYPE_SYSTEM:
         have_system_wake_locks = true;
         break;
@@ -328,7 +337,14 @@
     policy.mutable_battery_delays()->set_screen_lock_ms(0);
   }
 
-  if (have_screen_wake_locks || have_system_wake_locks) {
+  if (honor_screen_wake_locks_ && have_dim_wake_locks) {
+    policy.mutable_ac_delays()->set_screen_off_ms(0);
+    policy.mutable_ac_delays()->set_screen_lock_ms(0);
+    policy.mutable_battery_delays()->set_screen_off_ms(0);
+    policy.mutable_battery_delays()->set_screen_lock_ms(0);
+  }
+
+  if (have_screen_wake_locks || have_dim_wake_locks || have_system_wake_locks) {
     if (!policy.has_ac_idle_action() || policy.ac_idle_action() ==
         power_manager::PowerManagementPolicy_Action_SUSPEND) {
       policy.set_ac_idle_action(
diff --git a/chromeos/dbus/power_policy_controller.h b/chromeos/dbus/power_policy_controller.h
index 5437cd4..ec0ae2e2 100644
--- a/chromeos/dbus/power_policy_controller.h
+++ b/chromeos/dbus/power_policy_controller.h
@@ -98,11 +98,13 @@
   // and sends an updated policy. |description| is a human-readable description
   // of the reason the lock was created. Returns a unique ID that can be passed
   // to RemoveWakeLock() later.
+  // See the comment above WakeLock::Type for descriptions of the lock types.
   int AddScreenWakeLock(WakeLockReason reason, const std::string& description);
+  int AddDimWakeLock(WakeLockReason reason, const std::string& description);
   int AddSystemWakeLock(WakeLockReason reason, const std::string& description);
 
-  // Unregisters a request previously created via AddScreenWakeLock() or
-  // AddSystemWakeLock() and sends an updated policy.
+  // Unregisters a request previously created via an Add*WakeLock() call
+  // and sends an updated policy.
   void RemoveWakeLock(int id);
 
   // PowerManagerClient::Observer implementation:
@@ -114,11 +116,14 @@
 
   friend class PowerPrefsTest;
 
-  // Details about a wake lock added via AddScreenWakeLock() or
-  // AddSystemWakeLock().
+  // Details about a wake lock added via Add*WakeLock().
+  // SCREEN and DIM will keep the screen on and prevent it from locking.
+  // SCREEN will also prevent it from dimming. SYSTEM will prevent idle
+  // suspends, but the screen will turn off and lock normally.
   struct WakeLock {
     enum Type {
       TYPE_SCREEN,
+      TYPE_DIM,
       TYPE_SYSTEM,
     };
 
@@ -153,11 +158,11 @@
   // to details about the request.
   WakeLockMap wake_locks_;
 
-  // Should TYPE_SCREEN entries in |wake_locks_| be honored?  If false, screen
-  // wake locks are just treated as TYPE_SYSTEM instead.
+  // Should TYPE_SCREEN or TYPE_DIM entries in |wake_locks_| be honored?
+  // If false, screen wake locks are just treated as TYPE_SYSTEM instead.
   bool honor_screen_wake_locks_;
 
-  // Next ID to be used by AddScreenWakeLock() or AddSystemWakeLock().
+  // Next ID to be used by an Add*WakeLock() request.
   int next_wake_lock_id_;
 
   DISALLOW_COPY_AND_ASSIGN(PowerPolicyController);
diff --git a/chromeos/dbus/power_policy_controller_unittest.cc b/chromeos/dbus/power_policy_controller_unittest.cc
index 3352f21..7c6de2e 100644
--- a/chromeos/dbus/power_policy_controller_unittest.cc
+++ b/chromeos/dbus/power_policy_controller_unittest.cc
@@ -163,43 +163,111 @@
 }
 
 TEST_F(PowerPolicyControllerTest, WakeLocks) {
+  // If our highest lock type is system, we only worry about
+  // the idle action.
   const char kSystemWakeLockReason[] = "system";
+  power_manager::PowerManagementPolicy expected_policy_system;
+  expected_policy_system.set_ac_idle_action(
+      power_manager::PowerManagementPolicy_Action_DO_NOTHING);
+  expected_policy_system.set_battery_idle_action(
+      power_manager::PowerManagementPolicy_Action_DO_NOTHING);
+
+  // The dim lock type prevents the screen from turning off or
+  // locking, and we won't have an idle action.
+  const char kDimWakeLockReason[] = "dim";
+  power_manager::PowerManagementPolicy expected_policy_dim;
+  expected_policy_dim.set_ac_idle_action(
+      power_manager::PowerManagementPolicy_Action_DO_NOTHING);
+  expected_policy_dim.set_battery_idle_action(
+      power_manager::PowerManagementPolicy_Action_DO_NOTHING);
+  expected_policy_dim.mutable_ac_delays()->set_screen_off_ms(0);
+  expected_policy_dim.mutable_ac_delays()->set_screen_lock_ms(0);
+  expected_policy_dim.mutable_battery_delays()->set_screen_off_ms(0);
+  expected_policy_dim.mutable_battery_delays()->set_screen_lock_ms(0);
+
+  // The screen lock keeps the screen bright. We won't turn off,
+  // lock the screen or do anything for idle.
+  const char kScreenWakeLockReason[] = "screen";
+  power_manager::PowerManagementPolicy expected_policy_screen;
+  expected_policy_screen.set_ac_idle_action(
+      power_manager::PowerManagementPolicy_Action_DO_NOTHING);
+  expected_policy_screen.set_battery_idle_action(
+      power_manager::PowerManagementPolicy_Action_DO_NOTHING);
+  expected_policy_screen.mutable_ac_delays()->set_screen_dim_ms(0);
+  expected_policy_screen.mutable_ac_delays()->set_screen_off_ms(0);
+  expected_policy_screen.mutable_ac_delays()->set_screen_lock_ms(0);
+  expected_policy_screen.mutable_battery_delays()->set_screen_dim_ms(0);
+  expected_policy_screen.mutable_battery_delays()->set_screen_off_ms(0);
+  expected_policy_screen.mutable_battery_delays()->set_screen_lock_ms(0);
+
+  // With no locks our policy should be the default.
+  power_manager::PowerManagementPolicy expected_policy_none;
+
+  // There are eight different possibilities for combinations of
+  // different locks, as there are three types. We will go through
+  // each possibility by adding or removing one lock.
+
+  // System lock only.
   const int system_id = policy_controller_->AddSystemWakeLock(
       PowerPolicyController::REASON_OTHER, kSystemWakeLockReason);
-  power_manager::PowerManagementPolicy expected_policy;
-  expected_policy.set_ac_idle_action(
-      power_manager::PowerManagementPolicy_Action_DO_NOTHING);
-  expected_policy.set_battery_idle_action(
-      power_manager::PowerManagementPolicy_Action_DO_NOTHING);
-  expected_policy.set_reason(kSystemWakeLockReason);
-  EXPECT_EQ(PowerPolicyController::GetPolicyDebugString(expected_policy),
+  expected_policy_system.set_reason(kSystemWakeLockReason);
+  EXPECT_EQ(PowerPolicyController::GetPolicyDebugString(expected_policy_system),
             PowerPolicyController::GetPolicyDebugString(
                 fake_power_client_->policy()));
 
-  const char kScreenWakeLockReason[] = "screen";
+  // System and dim locks.
+  const int dim_id = policy_controller_->AddDimWakeLock(
+      PowerPolicyController::REASON_OTHER, kDimWakeLockReason);
+  expected_policy_dim.set_reason(std::string(kSystemWakeLockReason) + ", " +
+                                 kDimWakeLockReason);
+  EXPECT_EQ(PowerPolicyController::GetPolicyDebugString(expected_policy_dim),
+            PowerPolicyController::GetPolicyDebugString(
+                fake_power_client_->policy()));
+
+  // Dim lock only.
+  policy_controller_->RemoveWakeLock(system_id);
+  expected_policy_dim.set_reason(kDimWakeLockReason);
+  EXPECT_EQ(PowerPolicyController::GetPolicyDebugString(expected_policy_dim),
+            PowerPolicyController::GetPolicyDebugString(
+                fake_power_client_->policy()));
+
+  // Dim and screen locks.
   const int screen_id = policy_controller_->AddScreenWakeLock(
       PowerPolicyController::REASON_OTHER, kScreenWakeLockReason);
-  expected_policy.mutable_ac_delays()->set_screen_dim_ms(0);
-  expected_policy.mutable_ac_delays()->set_screen_off_ms(0);
-  expected_policy.mutable_ac_delays()->set_screen_lock_ms(0);
-  expected_policy.mutable_battery_delays()->set_screen_dim_ms(0);
-  expected_policy.mutable_battery_delays()->set_screen_off_ms(0);
-  expected_policy.mutable_battery_delays()->set_screen_lock_ms(0);
-  expected_policy.set_reason(std::string(kSystemWakeLockReason) + ", " +
-                             kScreenWakeLockReason);
-  EXPECT_EQ(PowerPolicyController::GetPolicyDebugString(expected_policy),
+  expected_policy_screen.set_reason(std::string(kDimWakeLockReason) + ", " +
+                                    kScreenWakeLockReason);
+  EXPECT_EQ(PowerPolicyController::GetPolicyDebugString(expected_policy_screen),
             PowerPolicyController::GetPolicyDebugString(
                 fake_power_client_->policy()));
 
-  policy_controller_->RemoveWakeLock(system_id);
-  expected_policy.set_reason(kScreenWakeLockReason);
-  EXPECT_EQ(PowerPolicyController::GetPolicyDebugString(expected_policy),
+  // System, dim and screen locks.
+  const int system_id_2 = policy_controller_->AddSystemWakeLock(
+      PowerPolicyController::REASON_OTHER, kSystemWakeLockReason);
+  expected_policy_screen.set_reason(std::string(kDimWakeLockReason) + ", " +
+                                    std::string(kScreenWakeLockReason) + ", " +
+                                    kSystemWakeLockReason);
+  EXPECT_EQ(PowerPolicyController::GetPolicyDebugString(expected_policy_screen),
             PowerPolicyController::GetPolicyDebugString(
                 fake_power_client_->policy()));
 
+  // System and screen locks.
+  policy_controller_->RemoveWakeLock(dim_id);
+  expected_policy_screen.set_reason(std::string(kScreenWakeLockReason) + ", " +
+                                    kSystemWakeLockReason);
+  EXPECT_EQ(PowerPolicyController::GetPolicyDebugString(expected_policy_screen),
+            PowerPolicyController::GetPolicyDebugString(
+                fake_power_client_->policy()));
+
+  // Screen lock only.
+  policy_controller_->RemoveWakeLock(system_id_2);
+  expected_policy_screen.set_reason(kScreenWakeLockReason);
+  EXPECT_EQ(PowerPolicyController::GetPolicyDebugString(expected_policy_screen),
+            PowerPolicyController::GetPolicyDebugString(
+                fake_power_client_->policy()));
+
+  // No locks.
   policy_controller_->RemoveWakeLock(screen_id);
-  expected_policy.Clear();
-  EXPECT_EQ(PowerPolicyController::GetPolicyDebugString(expected_policy),
+  EXPECT_EQ(PowerPolicyController::GetPolicyDebugString(expected_policy_none),
             PowerPolicyController::GetPolicyDebugString(
                 fake_power_client_->policy()));
 }
diff --git a/components/arc.gypi b/components/arc.gypi
index 7ad1264..7105b7b 100644
--- a/components/arc.gypi
+++ b/components/arc.gypi
@@ -32,5 +32,21 @@
         'arc/common/arc_notification_types.cc',
       ],
     },
+    {
+      # GN version: //components/arc_test_support
+      'target_name': 'arc_test_support',
+      'type': 'static_library',
+      'include_dirs': [
+        '..',
+      ],
+      'dependencies': [
+        '../base/base.gyp:base',
+        'arc',
+      ],
+      'sources': [
+        'arc/test/fake_arc_bridge_service.cc',
+        'arc/test/fake_arc_bridge_service.h',
+      ],
+    },
   ],
 }
diff --git a/components/arc/BUILD.gn b/components/arc/BUILD.gn
index fe11655..6ab92706 100644
--- a/components/arc/BUILD.gn
+++ b/components/arc/BUILD.gn
@@ -20,6 +20,19 @@
   ]
 }
 
+static_library("arc_test_support") {
+  testonly = true
+  sources = [
+    "test/fake_arc_bridge_service.cc",
+    "test/fake_arc_bridge_service.h",
+  ]
+
+  deps = [
+    ":arc",
+    "//base",
+  ]
+}
+
 source_set("unit_tests") {
   testonly = true
   sources = [
diff --git a/components/arc/test/fake_arc_bridge_service.cc b/components/arc/test/fake_arc_bridge_service.cc
new file mode 100644
index 0000000..ace3acf
--- /dev/null
+++ b/components/arc/test/fake_arc_bridge_service.cc
@@ -0,0 +1,145 @@
+// 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.
+
+#include "components/arc/test/fake_arc_bridge_service.h"
+
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/path_service.h"
+
+namespace arc {
+
+FakeArcBridgeService::FakeArcBridgeService() {
+}
+
+FakeArcBridgeService::~FakeArcBridgeService() {
+  if (state() != State::STOPPED) {
+    SetState(State::STOPPED);
+  }
+}
+
+void FakeArcBridgeService::DetectAvailability() {
+}
+
+void FakeArcBridgeService::HandleStartup() {
+}
+
+void FakeArcBridgeService::Shutdown() {
+}
+
+bool FakeArcBridgeService::RegisterInputDevice(const std::string& name,
+                                               const std::string& device_type,
+                                               base::ScopedFD fd) {
+  return true;
+}
+
+bool FakeArcBridgeService::SendNotificationEventToAndroid(
+    const std::string& key,
+    ArcNotificationEvent event) {
+  return true;
+}
+
+bool FakeArcBridgeService::RefreshAppList() {
+  ++refresh_app_list_count_;
+  return true;
+}
+
+bool FakeArcBridgeService::LaunchApp(const std::string& package,
+                                     const std::string& activity) {
+  launch_requests_.push_back(new Request(package, activity));
+  return true;
+}
+
+bool FakeArcBridgeService::RequestAppIcon(const std::string& package,
+                                          const std::string& activity,
+                                          ScaleFactor scale_factor) {
+  icon_requests_.push_back(new IconRequest(package, activity, scale_factor));
+  return true;
+}
+
+void FakeArcBridgeService::SetReady() {
+  SetState(State::READY);
+}
+
+void FakeArcBridgeService::SetStopped() {
+  SetState(State::STOPPED);
+}
+
+bool FakeArcBridgeService::HasObserver(const Observer* observer) {
+  return observer_list().HasObserver(observer);
+}
+
+bool FakeArcBridgeService::HasAppObserver(const AppObserver* observer) {
+  return app_observer_list().HasObserver(observer);
+}
+
+void FakeArcBridgeService::SendRefreshAppList(
+    const std::vector<AppInfo>& apps) {
+  FOR_EACH_OBSERVER(AppObserver, app_observer_list(), OnAppListRefreshed(apps));
+}
+
+bool FakeArcBridgeService::GenerateAndSendIcon(
+    const AppInfo& app,
+    ScaleFactor scale_factor,
+    std::string* png_data_as_string) {
+  CHECK(png_data_as_string != nullptr);
+  std::string icon_file_name;
+  switch(scale_factor) {
+  case SCALE_FACTOR_100P:
+    icon_file_name = "icon_100p.png";
+    break;
+  case SCALE_FACTOR_125P:
+    icon_file_name = "icon_125p.png";
+    break;
+  case SCALE_FACTOR_133P:
+    icon_file_name = "icon_133p.png";
+    break;
+  case SCALE_FACTOR_140P:
+    icon_file_name = "icon_140p.png";
+    break;
+  case SCALE_FACTOR_150P:
+    icon_file_name = "icon_150p.png";
+    break;
+  case SCALE_FACTOR_180P:
+    icon_file_name = "icon_180p.png";
+    break;
+  case SCALE_FACTOR_200P:
+    icon_file_name = "icon_200p.png";
+    break;
+  case SCALE_FACTOR_250P:
+    icon_file_name = "icon_250p.png";
+    break;
+  case SCALE_FACTOR_300P:
+    icon_file_name = "icon_300p.png";
+    break;
+  default:
+    NOTREACHED();
+    return false;
+  }
+
+  base::FilePath base_path;
+  CHECK(PathService::Get(base::DIR_SOURCE_ROOT, &base_path));
+  base::FilePath icon_file_path = base_path
+      .AppendASCII("components")
+      .AppendASCII("test")
+      .AppendASCII("data")
+      .AppendASCII("arc")
+      .AppendASCII(icon_file_name);
+  CHECK(base::PathExists(icon_file_path));
+  CHECK(base::ReadFileToString(icon_file_path, png_data_as_string));
+
+  std::vector<uint8_t> png_data(png_data_as_string->begin(),
+                                png_data_as_string->end());
+
+  FOR_EACH_OBSERVER(AppObserver,
+                    app_observer_list(),
+                    OnAppIcon(app.package,
+                              app.activity,
+                              scale_factor,
+                              png_data));
+
+  return true;
+}
+
+}  // namespace arc
diff --git a/components/arc/test/fake_arc_bridge_service.h b/components/arc/test/fake_arc_bridge_service.h
new file mode 100644
index 0000000..ef4e20d
--- /dev/null
+++ b/components/arc/test/fake_arc_bridge_service.h
@@ -0,0 +1,119 @@
+// 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.
+
+#ifndef COMPONENTS_ARC_TEST_FAKE_ARC_BRIDGE_SERVICE_H_
+#define COMPONENTS_ARC_TEST_FAKE_ARC_BRIDGE_SERVICE_H_
+
+#include <string>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/memory/scoped_vector.h"
+#include "components/arc/arc_bridge_service.h"
+
+namespace arc {
+
+class FakeArcBridgeService : public ArcBridgeService {
+ public:
+  class Request {
+   public:
+    Request(const std::string& package, const std::string& activity)
+        : package_(package),
+          activity_(activity) {
+    }
+
+    ~Request() {
+    }
+
+    const std::string& package() const { return package_; }
+
+    const std::string& activity() const { return activity_; }
+
+    bool IsForApp(const AppInfo& app_info) const {
+      return package_ == app_info.package && activity_ == app_info.activity;
+    }
+
+   private:
+    std::string package_;
+    std::string activity_;
+
+    DISALLOW_COPY_AND_ASSIGN(Request);
+  };
+
+  class IconRequest : public Request {
+   public:
+    IconRequest(const std::string& package,
+                const std::string& activity,
+                ScaleFactor scale_factor)
+        : Request(package, activity),
+          scale_factor_(scale_factor) {
+    }
+
+    ~IconRequest() {
+    }
+
+    int scale_factor() const { return scale_factor_; }
+
+   private:
+    int scale_factor_;
+
+    DISALLOW_COPY_AND_ASSIGN(IconRequest);
+  };
+
+  FakeArcBridgeService();
+  ~FakeArcBridgeService() override;
+
+  // arc::ArcBridgeService
+  void DetectAvailability() override;
+  void HandleStartup() override;
+  void Shutdown() override;
+  bool RegisterInputDevice(const std::string& name,
+                           const std::string& device_type,
+                           base::ScopedFD fd) override;
+  bool RefreshAppList() override;
+  bool LaunchApp(const std::string& package,
+                 const std::string& activity) override;
+  bool RequestAppIcon(const std::string& package,
+                      const std::string& activity,
+                      ScaleFactor scale_factor) override;
+  bool SendNotificationEventToAndroid(const std::string& key,
+                                      ArcNotificationEvent event) override;
+
+  int refresh_app_list_count() const { return refresh_app_list_count_; }
+
+  const ScopedVector<Request>& launch_requests() const {
+    return launch_requests_;
+  }
+
+  const ScopedVector<IconRequest>& icon_requests() const {
+    return icon_requests_;
+  }
+
+  void SetReady();
+
+  void SetStopped();
+
+  bool HasObserver(const Observer* observer);
+  bool HasAppObserver(const AppObserver* observer);
+
+  void SendRefreshAppList(const std::vector<AppInfo>& apps);
+
+  bool GenerateAndSendIcon(const AppInfo& app,
+                           ScaleFactor scale_factor,
+                           std::string* png_data);
+
+ private:
+  // Number of RefreshAppList calls.
+  int refresh_app_list_count_ = 0;
+  // Keeps information about launch requests.
+  ScopedVector<Request> launch_requests_;
+  // Keeps information about icon load requests.
+  ScopedVector<IconRequest> icon_requests_;
+
+  DISALLOW_COPY_AND_ASSIGN(FakeArcBridgeService);
+};
+
+}  // namespace arc
+
+#endif  // COMPONENTS_ARC_TEST_FAKE_ARC_BRIDGE_SERVICE_H_
diff --git a/components/autofill/content/renderer/autofill_agent.cc b/components/autofill/content/renderer/autofill_agent.cc
index a1ceea41..afb8274 100644
--- a/components/autofill/content/renderer/autofill_agent.cc
+++ b/components/autofill/content/renderer/autofill_agent.cc
@@ -386,10 +386,14 @@
 
 void AutofillAgent::textFieldDidChange(const WebFormControlElement& element) {
   DCHECK(toWebInputElement(&element) || form_util::IsTextAreaElement(element));
+
   if (ignore_text_changes_)
     return;
 
-  if (!IsUserGesture())
+  // Disregard text changes that aren't caused by user gestures or pastes. Note
+  // that pastes aren't necessarily user gestures because Blink's conception of
+  // user gestures is centered around creating new windows/tabs.
+  if (!IsUserGesture() && !render_frame()->IsPasting())
     return;
 
   // We post a task for doing the Autofill as the caret position is not set
@@ -731,9 +735,13 @@
                                        data_list_values,
                                        data_list_labels));
 
+  blink::WebRect bounding_box_in_window = element_.boundsInViewport();
+  render_frame()->GetRenderView()->convertViewportToWindow(
+      &bounding_box_in_window);
+
   Send(new AutofillHostMsg_QueryFormFieldAutofill(
       routing_id(), autofill_query_id_, form, field,
-      gfx::RectF(element_.boundsInViewport())));
+      gfx::RectF(bounding_box_in_window)));
 }
 
 void AutofillAgent::FillFieldWithValue(const base::string16& value,
diff --git a/components/autofill/content/renderer/password_autofill_agent.cc b/components/autofill/content/renderer/password_autofill_agent.cc
index a80fef1..4fe2a143 100644
--- a/components/autofill/content/renderer/password_autofill_agent.cc
+++ b/components/autofill/content/renderer/password_autofill_agent.cc
@@ -1438,9 +1438,13 @@
       username.isNull() ? base::string16()
                         : static_cast<base::string16>(user_input.value()));
 
+  blink::WebRect bounding_box_in_window = selected_element.boundsInViewport();
+  render_frame()->GetRenderView()->convertViewportToWindow(
+      &bounding_box_in_window);
+
   Send(new AutofillHostMsg_ShowPasswordSuggestions(
       routing_id(), key_it->second, field.text_direction, username_string,
-      options, gfx::RectF(selected_element.boundsInViewport())));
+      options, gfx::RectF(bounding_box_in_window)));
   username_query_prefix_ = username_string;
   return CanShowSuggestion(fill_data, username_string, show_all);
 }
diff --git a/components/autofill/content/renderer/password_generation_agent.cc b/components/autofill/content/renderer/password_generation_agent.cc
index 4d1c8cc..6ad50b5 100644
--- a/components/autofill/content/renderer/password_generation_agent.cc
+++ b/components/autofill/content/renderer/password_generation_agent.cc
@@ -411,18 +411,26 @@
 }
 
 void PasswordGenerationAgent::ShowGenerationPopup() {
+  blink::WebRect bounding_box_in_window =
+      generation_element_.boundsInViewport();
+  render_frame()->GetRenderView()->convertViewportToWindow(
+      &bounding_box_in_window);
+
   Send(new AutofillHostMsg_ShowPasswordGenerationPopup(
-      routing_id(), gfx::RectF(generation_element_.boundsInViewport()),
+      routing_id(), gfx::RectF(bounding_box_in_window),
       generation_element_.maxLength(), *generation_form_data_->form));
 
   generation_popup_shown_ = true;
 }
 
 void PasswordGenerationAgent::ShowEditingPopup() {
+  blink::WebRect bounding_box_in_window =
+      generation_element_.boundsInViewport();
+  render_frame()->GetRenderView()->convertViewportToWindow(
+      &bounding_box_in_window);
   Send(new AutofillHostMsg_ShowPasswordEditingPopup(
-      routing_id(), gfx::RectF(generation_element_.boundsInViewport()),
+      routing_id(), gfx::RectF(bounding_box_in_window),
       *generation_form_data_->form));
-
   editing_popup_shown_ = true;
 }
 
diff --git a/components/autofill/core/browser/autofill_field.cc b/components/autofill/core/browser/autofill_field.cc
index 5fd597d..41bc2fc0 100644
--- a/components/autofill/core/browser/autofill_field.cc
+++ b/components/autofill/core/browser/autofill_field.cc
@@ -20,6 +20,7 @@
 #include "components/autofill/core/browser/state_names.h"
 #include "components/autofill/core/common/autofill_l10n_util.h"
 #include "components/autofill/core/common/autofill_switches.h"
+#include "components/autofill/core/common/autofill_util.h"
 #include "grit/components_strings.h"
 #include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_data.h"
 #include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_formatter.h"
@@ -500,6 +501,13 @@
                                   FormFieldData* field_data) {
   AutofillType type = field.Type();
 
+  // Don't fill if autocomplete=off is set on |field| on desktop for non credit
+  // card related fields.
+  if (!field.should_autocomplete && IsDesktopPlatform() &&
+      (type.group() != CREDIT_CARD)) {
+    return false;
+  }
+
   if (type.GetStorableType() == PHONE_HOME_NUMBER) {
     FillPhoneNumberField(field, value, field_data);
     return true;
diff --git a/components/autofill/core/browser/autofill_field_unittest.cc b/components/autofill/core/browser/autofill_field_unittest.cc
index c65daaa..46009a2 100644
--- a/components/autofill/core/browser/autofill_field_unittest.cc
+++ b/components/autofill/core/browser/autofill_field_unittest.cc
@@ -9,6 +9,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "components/autofill/core/browser/autofill_type.h"
 #include "components/autofill/core/browser/field_types.h"
+#include "components/autofill/core/common/autofill_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 using base::ASCIIToUTF16;
@@ -129,11 +130,45 @@
   field.set_server_type(NAME_LAST);
   EXPECT_TRUE(field.IsFieldFillable());
 
-  // Field has autocomplete="off" set. Chrome ignores the attribute.
+  // Field has autocomplete="off" set. Since autofill was able to make a
+  // prediction, it is still considered a fillable field.
   field.should_autocomplete = false;
   EXPECT_TRUE(field.IsFieldFillable());
 }
 
+// Verify that non credit card related fields with the autocomplete attribute
+// set to off don't get filled on desktop.
+TEST(AutofillFieldTest, FillFormField_AutocompleteOff_AddressField) {
+  AutofillField field;
+  field.should_autocomplete = false;
+
+  // Non credit card related field.
+  AutofillField::FillFormField(field, ASCIIToUTF16("Test"), "en-US", "en-US",
+                               &field);
+
+  // Verifiy that the field is filled on mobile but not on desktop.
+  if (IsDesktopPlatform()) {
+    EXPECT_EQ(base::string16(), field.value);
+  } else {
+    EXPECT_EQ(ASCIIToUTF16("Test"), field.value);
+  }
+}
+
+// Verify that credit card related fields with the autocomplete attribute
+// set to off get filled.
+TEST(AutofillFieldTest, FillFormField_AutocompleteOff_CreditCardField) {
+  AutofillField field;
+  field.should_autocomplete = false;
+
+  // Credit card related field.
+  field.set_heuristic_type(CREDIT_CARD_NUMBER);
+  AutofillField::FillFormField(field, ASCIIToUTF16("4111111111111111"), "en-US",
+                               "en-US", &field);
+
+  // Verify that the field is filled.
+  EXPECT_EQ(ASCIIToUTF16("4111111111111111"), field.value);
+}
+
 TEST(AutofillFieldTest, FillPhoneNumber) {
   AutofillField field;
   field.SetHtmlType(HTML_TYPE_TEL_LOCAL_PREFIX, HtmlFieldMode());
diff --git a/components/autofill/core/browser/autofill_manager.cc b/components/autofill/core/browser/autofill_manager.cc
index e3c5e3c6..c3c0776 100644
--- a/components/autofill/core/browser/autofill_manager.cc
+++ b/components/autofill/core/browser/autofill_manager.cc
@@ -49,6 +49,7 @@
 #include "components/autofill/core/common/autofill_data_validation.h"
 #include "components/autofill/core/common/autofill_pref_names.h"
 #include "components/autofill/core/common/autofill_switches.h"
+#include "components/autofill/core/common/autofill_util.h"
 #include "components/autofill/core/common/form_data.h"
 #include "components/autofill/core/common/form_data_predictions.h"
 #include "components/autofill/core/common/form_field_data.h"
@@ -347,6 +348,9 @@
   if (!IsValidFormData(form) || !IsValidFormFieldData(field))
     return;
 
+  if (test_delegate_)
+    test_delegate_->OnTextFieldChanged();
+
   FormStructure* form_structure = NULL;
   AutofillField* autofill_field = NULL;
   if (!GetCachedFormAndField(form, field, &form_structure, &autofill_field))
@@ -407,6 +411,12 @@
       got_autofillable_form) {
     AutofillType type = autofill_field->Type();
     bool is_filling_credit_card = (type.group() == CREDIT_CARD);
+    // On desktop, don't return non credit card related suggestions for forms or
+    // fields that have the "autocomplete" attribute set to off.
+    if (IsDesktopPlatform() && !is_filling_credit_card &&
+        !field.should_autocomplete) {
+      return;
+    }
     if (is_filling_credit_card) {
       suggestions = GetCreditCardSuggestions(field, type);
     } else {
diff --git a/components/autofill/core/browser/autofill_manager_test_delegate.h b/components/autofill/core/browser/autofill_manager_test_delegate.h
index 222a8df..3e2ad09f 100644
--- a/components/autofill/core/browser/autofill_manager_test_delegate.h
+++ b/components/autofill/core/browser/autofill_manager_test_delegate.h
@@ -19,6 +19,9 @@
 
   // Called when a popup with Autofill suggestions is shown.
   virtual void DidShowSuggestions() = 0;
+
+  // Called when a text field change is detected.
+  virtual void OnTextFieldChanged() = 0;
 };
 
 }  // namespace autofill
diff --git a/components/autofill/core/browser/autofill_manager_unittest.cc b/components/autofill/core/browser/autofill_manager_unittest.cc
index 487eb108..87dccd9 100644
--- a/components/autofill/core/browser/autofill_manager_unittest.cc
+++ b/components/autofill/core/browser/autofill_manager_unittest.cc
@@ -35,6 +35,7 @@
 #include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
 #include "components/autofill/core/common/autofill_pref_names.h"
 #include "components/autofill/core/common/autofill_switches.h"
+#include "components/autofill/core/common/autofill_util.h"
 #include "components/autofill/core/common/form_data.h"
 #include "components/autofill/core/common/form_field_data.h"
 #include "grit/components_strings.h"
@@ -1895,6 +1896,89 @@
   }
 }
 
+// Test that non credit card related fields with the autocomplete attribute set
+// to off are not filled on desktop.
+TEST_F(AutofillManagerTest, FillAddressForm_AutocompleteOff) {
+  FormData address_form;
+  address_form.name = ASCIIToUTF16("MyForm");
+  address_form.origin = GURL("https://myform.com/form.html");
+  address_form.action = GURL("https://myform.com/submit.html");
+  FormFieldData field;
+  test::CreateTestFormField("First name", "firstname", "", "text", &field);
+  address_form.fields.push_back(field);
+  test::CreateTestFormField("Middle name", "middle", "", "text", &field);
+  field.should_autocomplete = false;
+  address_form.fields.push_back(field);
+  test::CreateTestFormField("Last name", "lastname", "", "text", &field);
+  field.should_autocomplete = true;
+  address_form.fields.push_back(field);
+  test::CreateTestFormField("Address Line 1", "addr1", "", "text", &field);
+  field.should_autocomplete = false;
+  address_form.fields.push_back(field);
+  std::vector<FormData> address_forms(1, address_form);
+  FormsSeen(address_forms);
+
+  // Fill the address form.
+  const char guid[] = "00000000-0000-0000-0000-000000000001";
+  int response_page_id = 0;
+  FormData response_data;
+  FillAutofillFormDataAndSaveResults(
+      kDefaultPageID, address_form, address_form.fields[0],
+      MakeFrontendID(std::string(), guid), &response_page_id, &response_data);
+
+  // The fist name should be filled.
+  ExpectFilledField("First name", "firstname", "Elvis", "text",
+                    response_data.fields[0]);
+
+  // The middle name should not be filled on desktop.
+  if (IsDesktopPlatform()) {
+    ExpectFilledField("Middle name", "middle", "", "text",
+                      response_data.fields[1]);
+  } else {
+    ExpectFilledField("Middle name", "middle", "Aaron", "text",
+                      response_data.fields[1]);
+  }
+
+  // The last name should be filled.
+  ExpectFilledField("Last name", "lastname", "Presley", "text",
+                    response_data.fields[2]);
+
+  // The address line 1 should not be filled on desktop.
+  if (IsDesktopPlatform()) {
+    ExpectFilledField("Address Line 1", "addr1", "", "text",
+                      response_data.fields[3]);
+  } else {
+    ExpectFilledField("Address Line 1", "addr1", "3734 Elvis Presley Blvd.",
+                      "text", response_data.fields[3]);
+  }
+}
+
+// Test that credit card fields are filled even if they have the autocomplete
+// attribute set to off.
+TEST_F(AutofillManagerTest, FillCreditCardForm_AutocompleteOff) {
+  // Set up our form data.
+  FormData form;
+  CreateTestCreditCardFormData(&form, true, false);
+
+  // Set the autocomplete=off on all fields.
+  for (FormFieldData field : form.fields)
+    field.should_autocomplete = false;
+
+  std::vector<FormData> forms(1, form);
+  FormsSeen(forms);
+
+  const char guid[] = "00000000-0000-0000-0000-000000000004";
+  int response_page_id = 0;
+  FormData response_data;
+  FillAutofillFormDataAndSaveResults(kDefaultPageID, form, *form.fields.begin(),
+                                     MakeFrontendID(guid, std::string()),
+                                     &response_page_id, &response_data);
+
+  // All fields should be filled.
+  ExpectFilledCreditCardFormElvis(response_page_id, response_data,
+                                  kDefaultPageID, false);
+}
+
 // Test that non-focusable field is ignored while inferring boundaries between
 // sections: http://crbug.com/231160
 TEST_F(AutofillManagerTest, FillFormWithNonFocusableFields) {
@@ -3870,4 +3954,72 @@
   EXPECT_FALSE(autofill_manager_->ShouldUploadForm(form_structure_3));
 }
 
+// Verify that no suggestions are shown on desktop for non credit card related
+// fields if the initiating field has the "autocomplete" attribute set to off.
+TEST_F(AutofillManagerTest, DisplaySuggestions_AutocompleteOff_AddressField) {
+  // Set up an address form.
+  FormData mixed_form;
+  mixed_form.name = ASCIIToUTF16("MyForm");
+  mixed_form.origin = GURL("https://myform.com/form.html");
+  mixed_form.action = GURL("https://myform.com/submit.html");
+  FormFieldData field;
+  test::CreateTestFormField("First name", "firstname", "", "text", &field);
+  field.should_autocomplete = false;
+  mixed_form.fields.push_back(field);
+  test::CreateTestFormField("Last name", "lastname", "", "text", &field);
+  field.should_autocomplete = true;
+  mixed_form.fields.push_back(field);
+  test::CreateTestFormField("Address", "address", "", "text", &field);
+  field.should_autocomplete = true;
+  mixed_form.fields.push_back(field);
+  std::vector<FormData> mixed_forms(1, mixed_form);
+  FormsSeen(mixed_forms);
+
+  // Suggestions should not be displayed on desktop for this field.
+  GetAutofillSuggestions(mixed_form, mixed_form.fields[0]);
+  if (IsDesktopPlatform()) {
+    EXPECT_FALSE(external_delegate_->on_suggestions_returned_seen());
+  } else {
+    EXPECT_TRUE(external_delegate_->on_suggestions_returned_seen());
+  }
+
+  // Suggestions should always be displayed for all the other fields.
+  for (size_t i = 1U; i < mixed_form.fields.size(); ++i) {
+    GetAutofillSuggestions(mixed_form, mixed_form.fields[i]);
+    EXPECT_TRUE(external_delegate_->on_suggestions_returned_seen());
+  }
+}
+
+// Verify that suggestions are shown on desktop for credit card related fields
+// even if the initiating field field has the "autocomplete" attribute set to
+// off.
+TEST_F(AutofillManagerTest,
+       DisplaySuggestions_AutocompleteOff_CreditCardField) {
+  // Set up a credit card form.
+  FormData mixed_form;
+  mixed_form.name = ASCIIToUTF16("MyForm");
+  mixed_form.origin = GURL("https://myform.com/form.html");
+  mixed_form.action = GURL("https://myform.com/submit.html");
+  FormFieldData field;
+  test::CreateTestFormField("Name on Card", "nameoncard", "", "text", &field);
+  field.should_autocomplete = false;
+  mixed_form.fields.push_back(field);
+  test::CreateTestFormField("Card Number", "cardnumber", "", "text", &field);
+  field.should_autocomplete = true;
+  mixed_form.fields.push_back(field);
+  test::CreateTestFormField("Expiration Month", "ccexpiresmonth", "", "text",
+                            &field);
+  field.should_autocomplete = false;
+  mixed_form.fields.push_back(field);
+  mixed_form.fields.push_back(field);
+  std::vector<FormData> mixed_forms(1, mixed_form);
+  FormsSeen(mixed_forms);
+
+  // Suggestions should always be displayed.
+  for (const FormFieldData& field : mixed_form.fields) {
+    GetAutofillSuggestions(mixed_form, field);
+    EXPECT_TRUE(external_delegate_->on_suggestions_returned_seen());
+  }
+}
+
 }  // namespace autofill
diff --git a/components/autofill/core/common/autofill_util.cc b/components/autofill/core/common/autofill_util.cc
index b2c3671..1359816 100644
--- a/components/autofill/core/common/autofill_util.cc
+++ b/components/autofill/core/common/autofill_util.cc
@@ -96,4 +96,12 @@
   return base::string16::npos;
 }
 
+bool IsDesktopPlatform() {
+#if defined(OS_ANDROID) || defined(OS_IOS)
+  return false;
+#else
+  return true;
+#endif
+}
+
 }  // namespace autofill
diff --git a/components/autofill/core/common/autofill_util.h b/components/autofill/core/common/autofill_util.h
index 81c3062..e29318d 100644
--- a/components/autofill/core/common/autofill_util.h
+++ b/components/autofill/core/common/autofill_util.h
@@ -36,6 +36,10 @@
                              const base::string16& field_contents,
                              bool case_sensitive);
 
+// Returns true if running on a desktop platform. Any platform that is not
+// Android or iOS is considered desktop.
+bool IsDesktopPlatform();
+
 }  // namespace autofill
 
 #endif  // COMPONENTS_AUTOFILL_CORE_COMMON_AUTOFILL_UTIL_H_
diff --git a/components/autofill/ios/browser/resources/autofill_controller.js b/components/autofill/ios/browser/resources/autofill_controller.js
index 16a4684..7c76203 100644
--- a/components/autofill/ios/browser/resources/autofill_controller.js
+++ b/components/autofill/ios/browser/resources/autofill_controller.js
@@ -175,27 +175,40 @@
 }
 
 /**
- * To avoid overly expensive computation, we impose a minimum number of
- * allowable fields.  The corresponding maximum number of allowable fields
- * is imposed by webFormElementToFormData().
+ * Determines whether the form is interesting enough to send to the browser for
+ * further operations.
  *
  * Unlike the C++ version, this version takes a required field count param,
  * instead of using a hard coded value.
  *
  * It is based on the logic in
- *     bool ShouldIgnoreForm(size_t num_editable_elements,
- *                           size_t num_control_elements);
+ *     bool IsFormInteresting(const FormData& form,
+ *                            size_t num_editable_elements);
  * in chromium/src/components/autofill/content/renderer/form_cache.cc
  *
+ * @param {AutofillFormData} form Form to examine.
  * @param {number} numEditableElements number of editable elements.
- * @param {number} numControlElements number of control elements.
  * @param {number} numFieldsRequired number of fields required.
- * @return {boolean} Whether to ignore the form or not.
+ * @return {boolean} Whether the form is sufficiently interesting.
  */
-function shouldIgnoreForm_(numEditableElements,
-                           numControlElements,
-                           numFieldsRequired) {
-  return numEditableElements < numFieldsRequired && numControlElements > 0;
+function isFormInteresting_(form, numEditableElements, numFieldsRequired) {
+  if (form.fields.length === 0) {
+    return false;
+  }
+
+  // If the form has at least one field with an autocomplete attribute, it is a
+  // candidate for autofill.
+  for (var i = 0; i < form.fields.length; ++i) {
+    if (form.fields['autocomplete_attribute'] != null &&
+        form.fields['autocomplete_attribute'].length > 0) {
+      return true;
+    }
+  }
+
+  // If there are no autocomplete attributes, the form needs to have at least
+  // the required number of editable fields for the prediction routines to be a
+  // candidate for autofill.
+  return numEditableElements >= numFieldsRequired;
 }
 
 /**
@@ -767,9 +780,8 @@
     var controlElements =
         __gCrWeb.autofill.extractAutofillableElementsInForm(formElement);
     var numEditableElements = scanFormControlElements_(controlElements);
-    if (shouldIgnoreForm_(numEditableElements,
-                          controlElements.length,
-                          minimumRequiredFields)) {
+
+    if (numEditableElements === 0) {
       continue;
     }
 
@@ -778,12 +790,13 @@
         frame, formElement, null, extractMask, form, null /* field */)) {
       continue;
     }
+
     numFieldsSeen += form['fields'].length;
     if (numFieldsSeen > __gCrWeb.autofill.MAX_PARSEABLE_FIELDS) {
       break;
     }
 
-    if (form.fields.length >= minimumRequiredFields) {
+    if (isFormInteresting_(form, numEditableElements, minimumRequiredFields)) {
       forms.push(form);
     }
   }
@@ -794,15 +807,16 @@
       getUnownedAutofillableFormFieldElements_(doc.all, fieldsets);
   var numEditableUnownedElements =
       scanFormControlElements_(unownedControlElements);
-  if (!shouldIgnoreForm_(numEditableUnownedElements,
-                         unownedControlElements.length,
-                         minimumRequiredFields)) {
+  if (numEditableUnownedElements > 0) {
     var unownedForm = new __gCrWeb['common'].JSONSafeObject;
-    if (unownedFormElementsAndFieldSetsToFormData_(
-        frame, fieldsets, unownedControlElements, extractMask, unownedForm)) {
+    var hasUnownedForm = unownedFormElementsAndFieldSetsToFormData_(
+        frame, fieldsets, unownedControlElements, extractMask, unownedForm);
+    if (hasUnownedForm) {
       numFieldsSeen += unownedForm['fields'].length;
       if (numFieldsSeen <= __gCrWeb.autofill.MAX_PARSEABLE_FIELDS) {
-        if (unownedForm.fields.length >= minimumRequiredFields) {
+        var interesting = isFormInteresting_(unownedForm,
+            numEditableUnownedElements, minimumRequiredFields);
+        if (interesting) {
           forms.push(unownedForm);
         }
       }
diff --git a/components/component_updater/component_updater_service.cc b/components/component_updater/component_updater_service.cc
index 1c49d26..490e5c4 100644
--- a/components/component_updater/component_updater_service.cc
+++ b/components/component_updater/component_updater_service.cc
@@ -352,7 +352,7 @@
   DCHECK(config);
   auto update_client = update_client::UpdateClientFactory(config);
   return scoped_ptr<ComponentUpdateService>(
-      new CrxUpdateService(config, update_client.Pass()));
+      new CrxUpdateService(config, std::move(update_client)));
 }
 
 }  // namespace component_updater
diff --git a/components/components_tests.gyp b/components/components_tests.gyp
index 1683204b..ce7d958 100644
--- a/components/components_tests.gyp
+++ b/components/components_tests.gyp
@@ -601,12 +601,12 @@
       'scheduler/base/task_queue_manager_delegate_for_test.h',
       'scheduler/base/task_queue_manager_unittest.cc',
       'scheduler/base/task_queue_selector_unittest.cc',
-      'scheduler/base/task_queue_sets_unittest.cc',
       'scheduler/base/test_always_fail_time_source.cc',
       'scheduler/base/test_always_fail_time_source.h',
       'scheduler/base/test_time_source.cc',
       'scheduler/base/test_time_source.h',
       'scheduler/base/time_domain_unittest.cc',
+      'scheduler/base/work_queue_sets_unittest.cc',
       'scheduler/child/idle_helper_unittest.cc',
       'scheduler/child/scheduler_helper_unittest.cc',
       'scheduler/child/scheduler_tqm_delegate_for_test.cc',
@@ -632,7 +632,7 @@
     'search_engines_unittest_sources': [
       'search_engines/default_search_manager_unittest.cc',
       'search_engines/default_search_pref_migration_unittest.cc',
-      'search_engines/detect_desktop_search_win_unittest.cc',
+      'search_engines/desktop_search_win_unittest.cc',
       'search_engines/keyword_table_unittest.cc',
       'search_engines/search_host_to_urls_map_unittest.cc',
       'search_engines/template_url_prepopulate_data_unittest.cc',
diff --git a/components/crash/content/app/crashpad_win.cc b/components/crash/content/app/crashpad_win.cc
index 684366e..07c235e 100644
--- a/components/crash/content/app/crashpad_win.cc
+++ b/components/crash/content/app/crashpad_win.cc
@@ -16,6 +16,7 @@
 #include "components/crash/content/app/crash_reporter_client.h"
 #include "third_party/crashpad/crashpad/client/crashpad_client.h"
 #include "third_party/crashpad/crashpad/client/crashpad_info.h"
+#include "third_party/crashpad/crashpad/client/simulate_crash_win.h"
 
 namespace crash_reporter {
 namespace internal {
@@ -68,8 +69,7 @@
     // In test binaries, use crashpad_handler directly. Otherwise, we launch
     // chrome.exe with --type=crashpad-handler.
     if (exe_file.BaseName().value() != FILE_PATH_LITERAL("chrome.exe")) {
-      base::FilePath exe_dir;
-      CHECK(PathService::Get(base::DIR_EXE, &exe_dir));
+      base::FilePath exe_dir = exe_file.DirName();
       exe_file = exe_dir.Append(FILE_PATH_LITERAL("crashpad_handler.exe"));
     } else {
       arguments.push_back("--type=crashpad-handler");
@@ -113,6 +113,60 @@
   return EXCEPTION_CONTINUE_SEARCH;
 }
 
+// TODO(scottmg): http://crbug.com/546288 These exported functions are for
+// compatibility with how Breakpad worked, but it seems like there's no need to
+// do the CreateRemoteThread() dance with a minor extension of the Crashpad API
+// (to just pass the pid we want a dump for). We should add that and then modify
+// hang_crash_dump_win.cc to work in a more direct manner.
+
+// Used for dumping a process state when there is no crash.
+extern "C" void __declspec(dllexport) __cdecl DumpProcessWithoutCrash() {
+  CRASHPAD_SIMULATE_CRASH();
+}
+
+namespace {
+
+// We need to prevent ICF from folding DumpForHangDebuggingThread() and
+// DumpProcessWithoutCrashThread() together, since that makes them
+// indistinguishable in crash dumps. We do this by making the function
+// bodies unique, and prevent optimization from shuffling things around.
+MSVC_DISABLE_OPTIMIZE()
+MSVC_PUSH_DISABLE_WARNING(4748)
+
+DWORD WINAPI DumpProcessWithoutCrashThread(void*) {
+  DumpProcessWithoutCrash();
+  return 0;
+}
+
+// The following two functions do exactly the same thing as the two above. But
+// we want the signatures to be different so that we can easily track them in
+// crash reports.
+// TODO(yzshen): Remove when enough information is collected and the hang rate
+// of pepper/renderer processes is reduced.
+DWORD WINAPI DumpForHangDebuggingThread(void*) {
+  DumpProcessWithoutCrash();
+  VLOG(1) << "dumped for hang debugging";
+  return 0;
+}
+
+MSVC_POP_WARNING()
+MSVC_ENABLE_OPTIMIZE()
+
+}  // namespace
+
+// Injects a thread into a remote process to dump state when there is no crash.
+extern "C" HANDLE __declspec(dllexport) __cdecl InjectDumpProcessWithoutCrash(
+    HANDLE process) {
+  return CreateRemoteThread(process, NULL, 0, DumpProcessWithoutCrashThread, 0,
+                            0, NULL);
+}
+
+extern "C" HANDLE __declspec(dllexport) __cdecl InjectDumpForHangDebugging(
+    HANDLE process) {
+  return CreateRemoteThread(process, NULL, 0, DumpForHangDebuggingThread, 0, 0,
+                            NULL);
+}
+
 #if defined(ARCH_CPU_X86_64)
 
 static int CrashForExceptionInNonABICompliantCodeRange(
diff --git a/components/exo/shell_surface.cc b/components/exo/shell_surface.cc
index 40bbd7f01..163b5588 100644
--- a/components/exo/shell_surface.cc
+++ b/components/exo/shell_surface.cc
@@ -180,6 +180,18 @@
   }
 }
 
+void ShellSurface::SetGeometry(const gfx::Rect& geometry) {
+  TRACE_EVENT1("exo", "ShellSurface::SetGeometry", "geometry",
+               geometry.ToString());
+
+  if (geometry.IsEmpty()) {
+    DLOG(WARNING) << "Surface geometry must be non-empty";
+    return;
+  }
+
+  geometry_ = geometry;
+}
+
 scoped_refptr<base::trace_event::TracedValue> ShellSurface::AsTracedValue()
     const {
   scoped_refptr<base::trace_event::TracedValue> value =
@@ -198,7 +210,8 @@
     // Update surface bounds and widget size.
     gfx::Point origin;
     views::View::ConvertPointToWidget(this, &origin);
-    surface_->SetBounds(gfx::Rect(origin, surface_->layer()->size()));
+    surface_->SetBounds(gfx::Rect(origin - geometry_.OffsetFromOrigin(),
+                                  surface_->layer()->size()));
     widget_->SetSize(widget_->non_client_view()->GetPreferredSize());
 
     // Show widget if not already visible.
@@ -248,6 +261,9 @@
 // views::Views overrides:
 
 gfx::Size ShellSurface::GetPreferredSize() const {
+  if (!geometry_.IsEmpty())
+    return geometry_.size();
+
   return surface_ ? surface_->GetPreferredSize() : gfx::Size();
 }
 
diff --git a/components/exo/shell_surface.h b/components/exo/shell_surface.h
index 1c2bad32..541dd11d 100644
--- a/components/exo/shell_surface.h
+++ b/components/exo/shell_surface.h
@@ -58,6 +58,10 @@
   // Start an interactive move of surface.
   void Move();
 
+  // Set geometry for surface. The geometry represents the "visible bounds"
+  // for the surface from the user's perspective.
+  void SetGeometry(const gfx::Rect& geometry);
+
   // Returns a trace value representing the state of the surface.
   scoped_refptr<base::trace_event::TracedValue> AsTracedValue() const;
 
@@ -84,6 +88,7 @@
   Surface* surface_;
   base::string16 title_;
   std::string application_id_;
+  gfx::Rect geometry_;
 
   DISALLOW_COPY_AND_ASSIGN(ShellSurface);
 };
diff --git a/components/exo/shell_surface_unittest.cc b/components/exo/shell_surface_unittest.cc
index 0f25a73..c8b6d46 100644
--- a/components/exo/shell_surface_unittest.cc
+++ b/components/exo/shell_surface_unittest.cc
@@ -117,5 +117,25 @@
   shell_surface->Move();
 }
 
+TEST_F(ShellSurfaceTest, SetGeometry) {
+  gfx::Size buffer_size(64, 64);
+  scoped_ptr<Buffer> buffer(new Buffer(
+      exo_test_helper()->CreateGpuMemoryBuffer(buffer_size), GL_TEXTURE_2D));
+  scoped_ptr<Surface> surface(new Surface);
+  scoped_ptr<ShellSurface> shell_surface(new ShellSurface(surface.get()));
+
+  shell_surface->SetToplevel();
+  gfx::Rect geometry(16, 16, 32, 32);
+  shell_surface->SetGeometry(geometry);
+  surface->Attach(buffer.get());
+  surface->Commit();
+  EXPECT_EQ(
+      geometry.size().ToString(),
+      shell_surface->GetWidget()->GetWindowBoundsInScreen().size().ToString());
+  EXPECT_EQ(gfx::Rect(gfx::Point() - geometry.OffsetFromOrigin(), buffer_size)
+                .ToString(),
+            surface->bounds().ToString());
+}
+
 }  // namespace
 }  // namespace exo
diff --git a/components/exo/surface.cc b/components/exo/surface.cc
index 717812c..7033b2a 100644
--- a/components/exo/surface.cc
+++ b/components/exo/surface.cc
@@ -88,9 +88,9 @@
       compositor_(nullptr),
       delegate_(nullptr) {
   SetType(ui::wm::WINDOW_TYPE_CONTROL);
+  SetName("ExoSurface");
   Init(ui::LAYER_SOLID_COLOR);
   set_owned_by_parent(false);
-  SetName("ExoSurface");
 }
 
 Surface::~Surface() {
diff --git a/components/exo/wayland/server.cc b/components/exo/wayland/server.cc
index 13a568d..4e36150c 100644
--- a/components/exo/wayland/server.cc
+++ b/components/exo/wayland/server.cc
@@ -758,7 +758,8 @@
                                      int32_t y,
                                      int32_t width,
                                      int32_t height) {
-  NOTIMPLEMENTED();
+  GetUserDataAs<ShellSurface>(resource)
+      ->SetGeometry(gfx::Rect(x, y, width, height));
 }
 
 void xdg_surface_set_maximized(wl_client* client, wl_resource* resource) {
diff --git a/components/html_viewer/BUILD.gn b/components/html_viewer/BUILD.gn
index 5f4a08a..820fc5a7 100644
--- a/components/html_viewer/BUILD.gn
+++ b/components/html_viewer/BUILD.gn
@@ -10,7 +10,6 @@
 
 if (is_android) {
   import("//build/config/android/rules.gni")
-  import("//mojo/generate_mojo_shell_assets_list.gni")
 }
 
 grit("html_viewer_resources_grit") {
@@ -63,8 +62,6 @@
     "blink_basic_type_converters.h",
     "blink_find_type_converters.cc",
     "blink_find_type_converters.h",
-    "blink_input_events_type_converters.cc",
-    "blink_input_events_type_converters.h",
     "blink_platform_impl.cc",
     "blink_platform_impl.h",
     "blink_resource_constants.h",
@@ -177,6 +174,7 @@
     "//mojo/application/public/cpp",
     "//mojo/application/public/interfaces",
     "//mojo/common",
+    "//mojo/converters/blink",
     "//mojo/converters/surfaces",
     "//mojo/gles2:headers",
     "//mojo/gpu:mojo_gles2_implementation",
@@ -316,6 +314,7 @@
     "//base/test:test_support",
     "//components/scheduler",
     "//gin",
+    "//mojo/converters/blink",
     "//mojo/converters/input_events",
     "//mojo/gles2",
     "//mojo/platform_handle:platform_handle_impl",
diff --git a/components/html_viewer/DEPS b/components/html_viewer/DEPS
index 21d04e94..e1e5a2f 100644
--- a/components/html_viewer/DEPS
+++ b/components/html_viewer/DEPS
@@ -24,6 +24,7 @@
   "+mojo/application",
   "+mojo/cc",
   "+mojo/common",
+  "+mojo/converters/blink",
   "+mojo/converters/geometry",
   "+mojo/converters/input_events",
   "+mojo/converters/network",
diff --git a/components/html_viewer/blink_input_events_type_converters.h b/components/html_viewer/blink_input_events_type_converters.h
deleted file mode 100644
index 9461bdc..0000000
--- a/components/html_viewer/blink_input_events_type_converters.h
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_HTML_VIEWER_BLINK_INPUT_EVENTS_TYPE_CONVERTERS_H_
-#define COMPONENTS_HTML_VIEWER_BLINK_INPUT_EVENTS_TYPE_CONVERTERS_H_
-
-#include "base/memory/scoped_ptr.h"
-#include "components/mus/public/interfaces/input_events.mojom.h"
-
-namespace blink {
-class WebInputEvent;
-}
-
-namespace mojo {
-
-template <>
-struct TypeConverter<scoped_ptr<blink::WebInputEvent>, mus::mojom::EventPtr> {
-  static scoped_ptr<blink::WebInputEvent> Convert(
-      const mus::mojom::EventPtr& input);
-};
-
-}  // namespace mojo
-
-#endif  // COMPONENTS_HTML_VIEWER_BLINK_INPUT_EVENTS_TYPE_CONVERTERS_H_
diff --git a/components/html_viewer/blink_platform_impl.cc b/components/html_viewer/blink_platform_impl.cc
index c50fb5e..443ba881 100644
--- a/components/html_viewer/blink_platform_impl.cc
+++ b/components/html_viewer/blink_platform_impl.cc
@@ -50,11 +50,11 @@
     bool initially_signaled = state == InitialState::Signaled;
     impl_.reset(new base::WaitableEvent(manual_reset, initially_signaled));
   }
-  virtual ~WebWaitableEventImpl() {}
+  ~WebWaitableEventImpl() override {}
 
-  virtual void reset() { impl_->Reset(); }
-  virtual void wait() { impl_->Wait(); }
-  virtual void signal() { impl_->Signal(); }
+  void reset() override { impl_->Reset(); }
+  void wait() override { impl_->Wait(); }
+  void signal() override { impl_->Signal(); }
 
   base::WaitableEvent* impl() {
     return impl_.get();
diff --git a/components/html_viewer/blink_platform_impl.h b/components/html_viewer/blink_platform_impl.h
index a0ceae4..25f078f 100644
--- a/components/html_viewer/blink_platform_impl.h
+++ b/components/html_viewer/blink_platform_impl.h
@@ -40,61 +40,61 @@
   BlinkPlatformImpl(GlobalState* global_state,
                     mojo::ApplicationImpl* app,
                     scheduler::RendererScheduler* renderer_scheduler);
-  virtual ~BlinkPlatformImpl();
+  ~BlinkPlatformImpl() override;
 
   // blink::Platform methods:
-  virtual blink::WebCookieJar* cookieJar();
-  virtual blink::WebClipboard* clipboard();
-  virtual blink::WebMimeRegistry* mimeRegistry();
-  virtual blink::WebThemeEngine* themeEngine();
-  virtual blink::WebString defaultLocale();
-  virtual blink::WebBlobRegistry* blobRegistry();
-  virtual double currentTimeSeconds();
-  virtual double monotonicallyIncreasingTimeSeconds();
-  virtual void cryptographicallyRandomValues(unsigned char* buffer,
-                                             size_t length);
-  virtual bool isThreadedCompositingEnabled();
-  virtual blink::WebCompositorSupport* compositorSupport();
+  blink::WebCookieJar* cookieJar() override;
+  blink::WebClipboard* clipboard() override;
+  blink::WebMimeRegistry* mimeRegistry() override;
+  blink::WebThemeEngine* themeEngine() override;
+  blink::WebString defaultLocale() override;
+  blink::WebBlobRegistry* blobRegistry() override;
+  double currentTimeSeconds() override;
+  double monotonicallyIncreasingTimeSeconds() override;
+  void cryptographicallyRandomValues(unsigned char* buffer,
+                                     size_t length) override;
+  bool isThreadedCompositingEnabled() override;
+  blink::WebCompositorSupport* compositorSupport() override;
   uint32_t getUniqueIdForProcess() override;
   void createMessageChannel(blink::WebMessagePortChannel** channel1,
                             blink::WebMessagePortChannel** channel2) override;
-  virtual blink::WebURLLoader* createURLLoader();
-  virtual blink::WebSocketHandle* createWebSocketHandle();
-  virtual blink::WebString userAgent();
-  virtual blink::WebData parseDataURL(
-      const blink::WebURL& url, blink::WebString& mime_type,
-      blink::WebString& charset);
-  virtual bool isReservedIPAddress(const blink::WebString& host) const;
-  virtual blink::WebURLError cancelledError(const blink::WebURL& url) const;
-  virtual blink::WebThread* createThread(const char* name);
-  virtual blink::WebThread* currentThread();
-  virtual void yieldCurrentThread();
-  virtual blink::WebWaitableEvent* createWaitableEvent(
+  blink::WebURLLoader* createURLLoader() override;
+  blink::WebSocketHandle* createWebSocketHandle() override;
+  blink::WebString userAgent() override;
+  blink::WebData parseDataURL(const blink::WebURL& url,
+                              blink::WebString& mime_type,
+                              blink::WebString& charset) override;
+  bool isReservedIPAddress(const blink::WebString& host) const override;
+  blink::WebURLError cancelledError(const blink::WebURL& url) const override;
+  blink::WebThread* createThread(const char* name) override;
+  blink::WebThread* currentThread() override;
+  void yieldCurrentThread() override;
+  blink::WebWaitableEvent* createWaitableEvent(
       blink::WebWaitableEvent::ResetPolicy policy,
-      blink::WebWaitableEvent::InitialState state);
-  virtual blink::WebWaitableEvent* waitMultipleEvents(
-      const blink::WebVector<blink::WebWaitableEvent*>& events);
-  virtual blink::WebScrollbarBehavior* scrollbarBehavior();
-  virtual const unsigned char* getTraceCategoryEnabledFlag(
-      const char* category_name);
-  virtual blink::WebGraphicsContext3D* createOffscreenGraphicsContext3D(
+      blink::WebWaitableEvent::InitialState state) override;
+  blink::WebWaitableEvent* waitMultipleEvents(
+      const blink::WebVector<blink::WebWaitableEvent*>& events) override;
+  blink::WebScrollbarBehavior* scrollbarBehavior() override;
+  const unsigned char* getTraceCategoryEnabledFlag(
+      const char* category_name) override;
+  blink::WebGraphicsContext3D* createOffscreenGraphicsContext3D(
       const blink::WebGraphicsContext3D::Attributes& attributes,
-      blink::WebGraphicsContext3D* share_context);
-  virtual blink::WebGraphicsContext3D* createOffscreenGraphicsContext3D(
+      blink::WebGraphicsContext3D* share_context) override;
+  blink::WebGraphicsContext3D* createOffscreenGraphicsContext3D(
       const blink::WebGraphicsContext3D::Attributes& attributes,
       blink::WebGraphicsContext3D* share_context,
-      blink::WebGraphicsContext3D::WebGraphicsInfo* gl_info);
-  virtual blink::WebGraphicsContext3D* createOffscreenGraphicsContext3D(
-      const blink::WebGraphicsContext3D::Attributes& attributes);
-  virtual blink::WebGraphicsContext3DProvider*
-      createSharedOffscreenGraphicsContext3DProvider();
-  virtual blink::WebData loadResource(const char* name);
-  virtual blink::WebGestureCurve* createFlingAnimationCurve(
+      blink::WebGraphicsContext3D::WebGraphicsInfo* gl_info) override;
+  blink::WebGraphicsContext3D* createOffscreenGraphicsContext3D(
+      const blink::WebGraphicsContext3D::Attributes& attributes) override;
+  blink::WebGraphicsContext3DProvider*
+  createSharedOffscreenGraphicsContext3DProvider() override;
+  blink::WebData loadResource(const char* name) override;
+  blink::WebGestureCurve* createFlingAnimationCurve(
       blink::WebGestureDevice device_source,
       const blink::WebFloatPoint& velocity,
-      const blink::WebSize& cumulative_scroll);
-  virtual blink::WebCrypto* crypto();
-  virtual blink::WebNotificationManager* notificationManager();
+      const blink::WebSize& cumulative_scroll) override;
+  blink::WebCrypto* crypto() override;
+  blink::WebNotificationManager* notificationManager() override;
 
  private:
   void UpdateWebThreadTLS(blink::WebThread* thread);
diff --git a/components/html_viewer/blink_settings_impl.cc b/components/html_viewer/blink_settings_impl.cc
index b6de9e3..a2b3180 100644
--- a/components/html_viewer/blink_settings_impl.cc
+++ b/components/html_viewer/blink_settings_impl.cc
@@ -244,8 +244,6 @@
   settings->setAccelerated2dCanvasMSAASampleCount(
       prefs.accelerated_2d_canvas_msaa_sample_count);
 
-  settings->setAsynchronousSpellCheckingEnabled(
-      prefs.asynchronous_spell_checking_enabled);
   settings->setUnifiedTextCheckerEnabled(prefs.unified_textchecker_enabled);
 
   // Tabs to link is not part of the settings. WebCore calls
diff --git a/components/html_viewer/devtools_agent_impl.h b/components/html_viewer/devtools_agent_impl.h
index 8b942d4..bcb429c 100644
--- a/components/html_viewer/devtools_agent_impl.h
+++ b/components/html_viewer/devtools_agent_impl.h
@@ -41,7 +41,7 @@
   void sendProtocolMessage(int session_id,
                            int call_id,
                            const blink::WebString& response,
-                           const blink::WebString& state);
+                           const blink::WebString& state) override;
 
   void OnConnectionError();
 
diff --git a/components/html_viewer/global_state.cc b/components/html_viewer/global_state.cc
index 4bbf4db..2a2261b 100644
--- a/components/html_viewer/global_state.cc
+++ b/components/html_viewer/global_state.cc
@@ -9,6 +9,8 @@
 #include "base/bind.h"
 #include "base/command_line.h"
 #include "base/logging.h"
+#include "cc/blink/web_layer_impl.h"
+#include "cc/layers/layer_settings.h"
 #include "components/html_viewer/blink_platform_impl.h"
 #include "components/html_viewer/blink_settings_impl.h"
 #include "components/html_viewer/media_factory.h"
@@ -128,6 +130,12 @@
   gpu_service_->GetGpuInfo(base::Bind(&GlobalState::GetGpuInfoCallback,
                                       base::Unretained(this)));
 
+  // Use new animation system (cc::AnimationHost).
+  cc::LayerSettings layer_settings;
+  layer_settings.use_compositor_animation_timelines = true;
+  cc_blink::WebLayerImpl::SetLayerSettings(layer_settings);
+  blink::WebRuntimeFeatures::enableCompositorAnimationTimelines(true);
+
   renderer_scheduler_ = scheduler::RendererScheduler::Create();
   blink_platform_.reset(
       new BlinkPlatformImpl(this, app_, renderer_scheduler_.get()));
diff --git a/components/html_viewer/html_frame.cc b/components/html_viewer/html_frame.cc
index 8050f145..1ddb997 100644
--- a/components/html_viewer/html_frame.cc
+++ b/components/html_viewer/html_frame.cc
@@ -17,7 +17,6 @@
 #include "components/html_viewer/ax_provider_impl.h"
 #include "components/html_viewer/blink_basic_type_converters.h"
 #include "components/html_viewer/blink_find_type_converters.h"
-#include "components/html_viewer/blink_input_events_type_converters.h"
 #include "components/html_viewer/blink_text_input_type_converters.h"
 #include "components/html_viewer/blink_url_request_type_converters.h"
 #include "components/html_viewer/devtools_agent_impl.h"
@@ -42,6 +41,7 @@
 #include "mojo/application/public/cpp/connect.h"
 #include "mojo/application/public/interfaces/shell.mojom.h"
 #include "mojo/common/common_type_converters.h"
+#include "mojo/converters/blink/blink_input_events_type_converters.h"
 #include "mojo/converters/geometry/geometry_type_converters.h"
 #include "third_party/WebKit/public/platform/Platform.h"
 #include "third_party/WebKit/public/platform/WebHTTPHeaderVisitor.h"
diff --git a/components/html_viewer/html_frame.h b/components/html_viewer/html_frame.h
index 34e33e3..9f108ac 100644
--- a/components/html_viewer/html_frame.h
+++ b/components/html_viewer/html_frame.h
@@ -152,59 +152,59 @@
                    base::TimeTicks navigation_start_time);
 
  protected:
-  virtual ~HTMLFrame();
+  ~HTMLFrame() override;
 
   // WebFrameClient methods:
-  virtual blink::WebMediaPlayer* createMediaPlayer(
+  blink::WebMediaPlayer* createMediaPlayer(
       blink::WebLocalFrame* frame,
       const blink::WebURL& url,
       blink::WebMediaPlayerClient* client,
       blink::WebMediaPlayerEncryptedMediaClient* encrypted_client,
       blink::WebContentDecryptionModule* initial_cdm,
-      const blink::WebString& sink_id);
-  virtual blink::WebFrame* createChildFrame(
+      const blink::WebString& sink_id) override;
+  blink::WebFrame* createChildFrame(
       blink::WebLocalFrame* parent,
       blink::WebTreeScopeType scope,
       const blink::WebString& frame_ame,
       blink::WebSandboxFlags sandbox_flags,
-      const blink::WebFrameOwnerProperties& frame_owner_properties);
-  virtual void frameDetached(blink::WebFrame* frame,
-                             blink::WebFrameClient::DetachType type);
-  virtual blink::WebCookieJar* cookieJar(blink::WebLocalFrame* frame);
-  virtual blink::WebNavigationPolicy decidePolicyForNavigation(
-      const NavigationPolicyInfo& info);
-  virtual bool hasPendingNavigation(blink::WebLocalFrame* frame);
-  virtual void didHandleOnloadEvents(blink::WebLocalFrame* frame);
-  virtual void didAddMessageToConsole(const blink::WebConsoleMessage& message,
-                                      const blink::WebString& source_name,
-                                      unsigned source_line,
-                                      const blink::WebString& stack_trace);
-  virtual void didFinishLoad(blink::WebLocalFrame* frame);
-  virtual void didNavigateWithinPage(blink::WebLocalFrame* frame,
-                                     const blink::WebHistoryItem& history_item,
-                                     blink::WebHistoryCommitType commit_type);
-  virtual blink::WebGeolocationClient* geolocationClient();
-  virtual blink::WebEncryptedMediaClient* encryptedMediaClient();
-  virtual void didStartLoading(bool to_different_document);
-  virtual void didStopLoading();
-  virtual void didChangeLoadProgress(double load_progress);
-  virtual void dispatchLoad();
-  virtual void didChangeName(blink::WebLocalFrame* frame,
-                             const blink::WebString& name);
-  virtual void didCommitProvisionalLoad(
+      const blink::WebFrameOwnerProperties& frame_owner_properties) override;
+  void frameDetached(blink::WebFrame* frame,
+                     blink::WebFrameClient::DetachType type) override;
+  blink::WebCookieJar* cookieJar(blink::WebLocalFrame* frame) override;
+  blink::WebNavigationPolicy decidePolicyForNavigation(
+      const NavigationPolicyInfo& info) override;
+  bool hasPendingNavigation(blink::WebLocalFrame* frame) override;
+  void didHandleOnloadEvents(blink::WebLocalFrame* frame) override;
+  void didAddMessageToConsole(const blink::WebConsoleMessage& message,
+                              const blink::WebString& source_name,
+                              unsigned source_line,
+                              const blink::WebString& stack_trace) override;
+  void didFinishLoad(blink::WebLocalFrame* frame) override;
+  void didNavigateWithinPage(blink::WebLocalFrame* frame,
+                             const blink::WebHistoryItem& history_item,
+                             blink::WebHistoryCommitType commit_type) override;
+  blink::WebGeolocationClient* geolocationClient() override;
+  blink::WebEncryptedMediaClient* encryptedMediaClient() override;
+  void didStartLoading(bool to_different_document) override;
+  void didStopLoading() override;
+  void didChangeLoadProgress(double load_progress) override;
+  void dispatchLoad() override;
+  void didChangeName(blink::WebLocalFrame* frame,
+                     const blink::WebString& name) override;
+  void didCommitProvisionalLoad(
       blink::WebLocalFrame* frame,
       const blink::WebHistoryItem& item,
-      blink::WebHistoryCommitType commit_type);
-  virtual void didReceiveTitle(blink::WebLocalFrame* frame,
-                               const blink::WebString& title,
-                               blink::WebTextDirection direction);
-  virtual void reportFindInFrameMatchCount(int identifier,
-                                           int count,
-                                           bool finalUpdate);
-  virtual void reportFindInPageSelection(int identifier,
-                                         int activeMatchOrdinal,
-                                         const blink::WebRect& selection);
-  virtual bool shouldSearchSingleFrame();
+      blink::WebHistoryCommitType commit_type) override;
+  void didReceiveTitle(blink::WebLocalFrame* frame,
+                       const blink::WebString& title,
+                       blink::WebTextDirection direction) override;
+  void reportFindInFrameMatchCount(int identifier,
+                                   int count,
+                                   bool finalUpdate) override;
+  void reportFindInPageSelection(int identifier,
+                                 int activeMatchOrdinal,
+                                 const blink::WebRect& selection) override;
+  bool shouldSearchSingleFrame() override;
 
  private:
   friend class HTMLFrameTreeManager;
@@ -310,17 +310,17 @@
   void StopHighlightingFindResults() override;
 
   // blink::WebRemoteFrameClient:
-  virtual void frameDetached(blink::WebRemoteFrameClient::DetachType type);
-  virtual void postMessageEvent(blink::WebLocalFrame* source_web_frame,
-                                blink::WebRemoteFrame* target_web_frame,
-                                blink::WebSecurityOrigin target_origin,
-                                blink::WebDOMMessageEvent event);
-  virtual void initializeChildFrame(const blink::WebRect& frame_rect,
-                                    float scale_factor);
-  virtual void navigate(const blink::WebURLRequest& request,
-                        bool should_replace_current_entry);
-  virtual void reload(bool ignore_cache, bool is_client_redirect);
-  virtual void frameRectsChanged(const blink::WebRect& frame_rect);
+  void frameDetached(blink::WebRemoteFrameClient::DetachType type) override;
+  void postMessageEvent(blink::WebLocalFrame* source_web_frame,
+                        blink::WebRemoteFrame* target_web_frame,
+                        blink::WebSecurityOrigin target_origin,
+                        blink::WebDOMMessageEvent event) override;
+  void initializeChildFrame(const blink::WebRect& frame_rect,
+                            float scale_factor) override;
+  void navigate(const blink::WebURLRequest& request,
+                bool should_replace_current_entry) override;
+  void reload(bool ignore_cache, bool is_client_redirect) override;
+  void frameRectsChanged(const blink::WebRect& frame_rect) override;
 
   HTMLFrameTreeManager* frame_tree_manager_;
   HTMLFrame* parent_;
diff --git a/components/html_viewer/html_widget.h b/components/html_viewer/html_widget.h
index 7ae9f4c..03cd280 100644
--- a/components/html_viewer/html_widget.h
+++ b/components/html_viewer/html_widget.h
@@ -45,8 +45,8 @@
 
  private:
   // WebViewClient methods:
-  virtual blink::WebStorageNamespace* createSessionStorageNamespace();
-  virtual bool allowsBrokenNullLayerTreeView() const;
+  blink::WebStorageNamespace* createSessionStorageNamespace() override;
+  bool allowsBrokenNullLayerTreeView() const override;
 
   // HTMLWidget:
   blink::WebWidget* GetWidget() override;
@@ -79,15 +79,15 @@
 
  protected:
   // WebViewClient methods:
-  virtual blink::WebStorageNamespace* createSessionStorageNamespace();
-  virtual void initializeLayerTreeView();
-  virtual blink::WebLayerTreeView* layerTreeView();
-  virtual void didMeaningfulLayout(blink::WebMeaningfulLayout layout_type);
-  virtual void resetInputMethod();
-  virtual void didHandleGestureEvent(const blink::WebGestureEvent& event,
-                                     bool event_cancelled);
-  virtual void didUpdateTextOfFocusedElementByNonUserInput();
-  virtual void showImeIfNeeded();
+  blink::WebStorageNamespace* createSessionStorageNamespace() override;
+  void initializeLayerTreeView() override;
+  blink::WebLayerTreeView* layerTreeView() override;
+  void didMeaningfulLayout(blink::WebMeaningfulLayout layout_type) override;
+  void resetInputMethod() override;
+  void didHandleGestureEvent(const blink::WebGestureEvent& event,
+                             bool event_cancelled) override;
+  void didUpdateTextOfFocusedElementByNonUserInput() override;
+  void showImeIfNeeded() override;
 
  private:
   // HTMLWidget:
@@ -119,13 +119,13 @@
   void OnWindowBoundsChanged(mus::Window* window) override;
 
   // WebWidgetClient:
-  virtual void initializeLayerTreeView();
-  virtual blink::WebLayerTreeView* layerTreeView();
-  virtual void resetInputMethod();
-  virtual void didHandleGestureEvent(const blink::WebGestureEvent& event,
-                                     bool event_cancelled);
-  virtual void didUpdateTextOfFocusedElementByNonUserInput();
-  virtual void showImeIfNeeded();
+  void initializeLayerTreeView() override;
+  blink::WebLayerTreeView* layerTreeView() override;
+  void resetInputMethod() override;
+  void didHandleGestureEvent(const blink::WebGestureEvent& event,
+                             bool event_cancelled) override;
+  void didUpdateTextOfFocusedElementByNonUserInput() override;
+  void showImeIfNeeded() override;
 
   mojo::ApplicationImpl* app_;
   GlobalState* global_state_;
diff --git a/components/html_viewer/ime_controller.cc b/components/html_viewer/ime_controller.cc
index 3b65a5a..da6e7b14 100644
--- a/components/html_viewer/ime_controller.cc
+++ b/components/html_viewer/ime_controller.cc
@@ -4,9 +4,9 @@
 
 #include "components/html_viewer/ime_controller.h"
 
-#include "components/html_viewer/blink_input_events_type_converters.h"
 #include "components/html_viewer/blink_text_input_type_converters.h"
 #include "components/mus/public/cpp/window.h"
+#include "mojo/converters/blink/blink_input_events_type_converters.h"
 #include "third_party/WebKit/public/web/WebInputEvent.h"
 #include "third_party/WebKit/public/web/WebWidget.h"
 
diff --git a/components/html_viewer/input_events_unittest.cc b/components/html_viewer/input_events_unittest.cc
index afaf724..4a28bbec 100644
--- a/components/html_viewer/input_events_unittest.cc
+++ b/components/html_viewer/input_events_unittest.cc
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 #include "base/memory/scoped_ptr.h"
-#include "components/html_viewer/blink_input_events_type_converters.h"
+#include "mojo/converters/blink/blink_input_events_type_converters.h"
 #include "mojo/converters/input_events/input_events_type_converters.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/WebKit/public/web/WebInputEvent.h"
diff --git a/components/html_viewer/mock_web_blob_registry_impl.h b/components/html_viewer/mock_web_blob_registry_impl.h
index 1a8ee38..687e685 100644
--- a/components/html_viewer/mock_web_blob_registry_impl.h
+++ b/components/html_viewer/mock_web_blob_registry_impl.h
@@ -22,28 +22,28 @@
 class MockWebBlobRegistryImpl : public blink::WebBlobRegistry {
  public:
   MockWebBlobRegistryImpl();
-  virtual ~MockWebBlobRegistryImpl();
+  ~MockWebBlobRegistryImpl() override;
 
-  virtual void registerBlobData(const blink::WebString& uuid,
-                                const blink::WebBlobData& data);
-  virtual void addBlobDataRef(const blink::WebString& uuid);
-  virtual void removeBlobDataRef(const blink::WebString& uuid);
-  virtual void registerPublicBlobURL(const blink::WebURL&,
-                                     const blink::WebString& uuid);
-  virtual void revokePublicBlobURL(const blink::WebURL&);
+  void registerBlobData(const blink::WebString& uuid,
+                        const blink::WebBlobData& data) override;
+  void addBlobDataRef(const blink::WebString& uuid) override;
+  void removeBlobDataRef(const blink::WebString& uuid) override;
+  void registerPublicBlobURL(const blink::WebURL&,
+                             const blink::WebString& uuid) override;
+  void revokePublicBlobURL(const blink::WebURL&) override;
 
   // Additional support for Streams.
-  virtual void registerStreamURL(const blink::WebURL& url,
-                                 const blink::WebString& content_type);
-  virtual void registerStreamURL(const blink::WebURL& url,
-                                 const blink::WebURL& src_url);
-  virtual void addDataToStream(const blink::WebURL& url,
-                               const char* data,
-                               size_t length);
-  virtual void flushStream(const blink::WebURL& url);
-  virtual void finalizeStream(const blink::WebURL& url);
-  virtual void abortStream(const blink::WebURL& url);
-  virtual void unregisterStreamURL(const blink::WebURL& url);
+  void registerStreamURL(const blink::WebURL& url,
+                         const blink::WebString& content_type) override;
+  void registerStreamURL(const blink::WebURL& url,
+                         const blink::WebURL& src_url) override;
+  void addDataToStream(const blink::WebURL& url,
+                       const char* data,
+                       size_t length) override;
+  void flushStream(const blink::WebURL& url) override;
+  void finalizeStream(const blink::WebURL& url) override;
+  void abortStream(const blink::WebURL& url) override;
+  void unregisterStreamURL(const blink::WebURL& url) override;
 
   bool GetUUIDForURL(const blink::WebURL& url, blink::WebString* uuid) const;
   bool GetBlobItems(const blink::WebString& uuid,
diff --git a/components/html_viewer/test_html_viewer_impl.cc b/components/html_viewer/test_html_viewer_impl.cc
index b006255..b8f98ee 100644
--- a/components/html_viewer/test_html_viewer_impl.cc
+++ b/components/html_viewer/test_html_viewer_impl.cc
@@ -42,11 +42,12 @@
   ExecutionCallbackImpl(TestHTMLViewerImpl* host,
                         const mojo::Callback<void(mojo::String)>& callback)
       : host_(host), callback_(callback) {}
-  virtual ~ExecutionCallbackImpl() {}
+  ~ExecutionCallbackImpl() override {}
 
  private:
   // blink::WebScriptExecutionCallback:
-  virtual void completed(const blink::WebVector<v8::Local<v8::Value>>& result) {
+  void completed(
+      const blink::WebVector<v8::Local<v8::Value>>& result) override {
     mojo::String callback_result;
     if (!result.isEmpty())
       callback_result = V8ValueToJSONString(host_->web_frame_, result);
diff --git a/components/html_viewer/web_clipboard_impl.h b/components/html_viewer/web_clipboard_impl.h
index 407ef81..fd1e18a 100644
--- a/components/html_viewer/web_clipboard_impl.h
+++ b/components/html_viewer/web_clipboard_impl.h
@@ -16,24 +16,24 @@
   virtual ~WebClipboardImpl();
 
   // blink::WebClipboard methods:
-  virtual uint64_t sequenceNumber(Buffer);
-  virtual bool isFormatAvailable(Format, Buffer);
-  virtual blink::WebVector<blink::WebString> readAvailableTypes(
+  uint64_t sequenceNumber(Buffer) override;
+  bool isFormatAvailable(Format, Buffer) override;
+  blink::WebVector<blink::WebString> readAvailableTypes(
       Buffer buffer,
-      bool* contains_filenames);
-  virtual blink::WebString readPlainText(Buffer buffer);
-  virtual blink::WebString readHTML(Buffer buffer,
-                                    blink::WebURL* page_url,
-                                    unsigned* fragment_start,
-                                    unsigned* fragment_end);
+      bool* contains_filenames) override;
+  blink::WebString readPlainText(Buffer buffer) override;
+  blink::WebString readHTML(Buffer buffer,
+                            blink::WebURL* page_url,
+                            unsigned* fragment_start,
+                            unsigned* fragment_end) override;
   // TODO(erg): readImage()
-  virtual blink::WebString readCustomData(Buffer buffer,
-                                          const blink::WebString& type);
-  virtual void writePlainText(const blink::WebString& plain_text);
-  virtual void writeHTML(const blink::WebString& html_text,
-                         const blink::WebURL& source_url,
-                         const blink::WebString& plain_text,
-                         bool write_smart_paste);
+  blink::WebString readCustomData(Buffer buffer,
+                                  const blink::WebString& type) override;
+  void writePlainText(const blink::WebString& plain_text) override;
+  void writeHTML(const blink::WebString& html_text,
+                 const blink::WebURL& source_url,
+                 const blink::WebString& plain_text,
+                 bool write_smart_paste) override;
 
  private:
   // Changes webkit buffers to mojo Clipboard::Types.
diff --git a/components/html_viewer/web_cookie_jar_impl.h b/components/html_viewer/web_cookie_jar_impl.h
index bec897e..d8ae21ba 100644
--- a/components/html_viewer/web_cookie_jar_impl.h
+++ b/components/html_viewer/web_cookie_jar_impl.h
@@ -16,15 +16,15 @@
   virtual ~WebCookieJarImpl();
 
   // blink::WebCookieJar methods:
-  virtual void setCookie(const blink::WebURL& url,
-                         const blink::WebURL& first_party_for_cookies,
-                         const blink::WebString& cookie);
-  virtual blink::WebString cookies(
+  void setCookie(const blink::WebURL& url,
+                 const blink::WebURL& first_party_for_cookies,
+                 const blink::WebString& cookie) override;
+  blink::WebString cookies(
       const blink::WebURL& url,
-      const blink::WebURL& first_party_for_cookies);
-  virtual blink::WebString cookieRequestHeaderFieldValue(
+      const blink::WebURL& first_party_for_cookies) override;
+  blink::WebString cookieRequestHeaderFieldValue(
       const blink::WebURL& url,
-      const blink::WebURL& first_party_for_cookies);
+      const blink::WebURL& first_party_for_cookies) override;
 
  private:
   mojo::CookieStorePtr store_;
diff --git a/components/html_viewer/web_graphics_context_3d_command_buffer_impl.h b/components/html_viewer/web_graphics_context_3d_command_buffer_impl.h
index 37076df..adcd03db 100644
--- a/components/html_viewer/web_graphics_context_3d_command_buffer_impl.h
+++ b/components/html_viewer/web_graphics_context_3d_command_buffer_impl.h
@@ -44,7 +44,7 @@
       const GURL& active_url,
       const blink::WebGraphicsContext3D::Attributes& attributes,
       blink::WebGraphicsContext3D* share_context);
-  virtual ~WebGraphicsContext3DCommandBufferImpl();
+  ~WebGraphicsContext3DCommandBufferImpl() override;
 
   static void ContextLostThunk(void* closure) {
     static_cast<WebGraphicsContext3DCommandBufferImpl*>(closure)->ContextLost();
diff --git a/components/html_viewer/web_layer_tree_view_impl.cc b/components/html_viewer/web_layer_tree_view_impl.cc
index c379bc9b..2f793b8 100644
--- a/components/html_viewer/web_layer_tree_view_impl.cc
+++ b/components/html_viewer/web_layer_tree_view_impl.cc
@@ -41,6 +41,9 @@
   // to keep content always crisp when possible.
   settings.layer_transforms_should_scale_layer_contents = true;
 
+  // Use new animation system (cc::AnimationHost).
+  settings.use_compositor_animation_timelines = true;
+
   // TODO(rjkroege): Not having a shared tile transport breaks
   // software compositing. Add bitmap transport support.
   cc::SharedBitmapManager* shared_bitmap_manager = nullptr;
diff --git a/components/html_viewer/web_layer_tree_view_impl.h b/components/html_viewer/web_layer_tree_view_impl.h
index aa2ee3cb..bcd833b 100644
--- a/components/html_viewer/web_layer_tree_view_impl.h
+++ b/components/html_viewer/web_layer_tree_view_impl.h
@@ -72,40 +72,40 @@
       override {}
 
   // blink::WebLayerTreeView implementation.
-  virtual void setRootLayer(const blink::WebLayer& layer);
-  virtual void clearRootLayer();
-  virtual void setViewportSize(const blink::WebSize& device_viewport_size);
-  virtual void setDeviceScaleFactor(float);
+  void setRootLayer(const blink::WebLayer& layer) override;
+  void clearRootLayer() override;
+  void setViewportSize(const blink::WebSize& device_viewport_size) override;
+  void setDeviceScaleFactor(float) override;
   virtual float deviceScaleFactor() const;
-  virtual void setBackgroundColor(blink::WebColor color);
-  virtual void setHasTransparentBackground(bool has_transparent_background);
-  virtual void setVisible(bool visible);
-  virtual void setPageScaleFactorAndLimits(float page_scale_factor,
-                                           float minimum,
-                                           float maximum);
-  virtual void startPageScaleAnimation(const blink::WebPoint& destination,
-                                       bool use_anchor,
-                                       float new_page_scale,
-                                       double duration_sec);
-  virtual void heuristicsForGpuRasterizationUpdated(bool matches_heuristic) {}
-  virtual void setNeedsAnimate();
-  virtual void didStopFlinging() {}
-  virtual void compositeAndReadbackAsync(
-      blink::WebCompositeAndReadbackAsyncCallback* callback) {}
-  virtual void setDeferCommits(bool defer_commits) {}
-  virtual void registerForAnimations(blink::WebLayer* layer);
-  virtual void registerViewportLayers(
+  void setBackgroundColor(blink::WebColor color) override;
+  void setHasTransparentBackground(bool has_transparent_background) override;
+  void setVisible(bool visible) override;
+  void setPageScaleFactorAndLimits(float page_scale_factor,
+                                   float minimum,
+                                   float maximum) override;
+  void startPageScaleAnimation(const blink::WebPoint& destination,
+                               bool use_anchor,
+                               float new_page_scale,
+                               double duration_sec) override;
+  void heuristicsForGpuRasterizationUpdated(bool matches_heuristic) override {}
+  void setNeedsAnimate() override;
+  void didStopFlinging() override {}
+  void compositeAndReadbackAsync(
+      blink::WebCompositeAndReadbackAsyncCallback* callback) override {}
+  void setDeferCommits(bool defer_commits) override {}
+  void registerForAnimations(blink::WebLayer* layer) override;
+  void registerViewportLayers(
       const blink::WebLayer* overscrollElasticityLayer,
       const blink::WebLayer* pageScaleLayerLayer,
       const blink::WebLayer* innerViewportScrollLayer,
-      const blink::WebLayer* outerViewportScrollLayer);
-  virtual void clearViewportLayers();
-  virtual void registerSelection(const blink::WebSelection& selection) {}
-  virtual void clearSelection() {}
-  virtual void setShowFPSCounter(bool) {}
-  virtual void setShowPaintRects(bool) {}
-  virtual void setShowDebugBorders(bool) {}
-  virtual void setShowScrollBottleneckRects(bool) {}
+      const blink::WebLayer* outerViewportScrollLayer) override;
+  void clearViewportLayers() override;
+  void registerSelection(const blink::WebSelection& selection) override {}
+  void clearSelection() override {}
+  void setShowFPSCounter(bool) override {}
+  void setShowPaintRects(bool) override {}
+  void setShowDebugBorders(bool) override {}
+  void setShowScrollBottleneckRects(bool) override {}
 
  private:
   // widget_ and window_ will outlive us.
diff --git a/components/html_viewer/web_mime_registry_impl.h b/components/html_viewer/web_mime_registry_impl.h
index 0440adcd..f0214880 100644
--- a/components/html_viewer/web_mime_registry_impl.h
+++ b/components/html_viewer/web_mime_registry_impl.h
@@ -16,26 +16,26 @@
   virtual ~WebMimeRegistryImpl() {}
 
   // WebMimeRegistry methods:
-  virtual blink::WebMimeRegistry::SupportsType supportsMIMEType(
-      const blink::WebString& mime_type);
-  virtual blink::WebMimeRegistry::SupportsType supportsImageMIMEType(
-      const blink::WebString& mime_type);
-  virtual blink::WebMimeRegistry::SupportsType supportsImagePrefixedMIMEType(
-      const blink::WebString& mime_type);
-  virtual blink::WebMimeRegistry::SupportsType supportsJavaScriptMIMEType(
-      const blink::WebString& mime_type);
-  virtual blink::WebMimeRegistry::SupportsType supportsMediaMIMEType(
+  blink::WebMimeRegistry::SupportsType supportsMIMEType(
+      const blink::WebString& mime_type) override;
+  blink::WebMimeRegistry::SupportsType supportsImageMIMEType(
+      const blink::WebString& mime_type) override;
+  blink::WebMimeRegistry::SupportsType supportsImagePrefixedMIMEType(
+      const blink::WebString& mime_type) override;
+  blink::WebMimeRegistry::SupportsType supportsJavaScriptMIMEType(
+      const blink::WebString& mime_type) override;
+  blink::WebMimeRegistry::SupportsType supportsMediaMIMEType(
       const blink::WebString& mime_type,
       const blink::WebString& codecs,
-      const blink::WebString& key_system);
-  virtual bool supportsMediaSourceMIMEType(const blink::WebString& mime_type,
-                                           const blink::WebString& codecs);
-  virtual blink::WebMimeRegistry::SupportsType supportsNonImageMIMEType(
-      const blink::WebString& mime_type);
-  virtual blink::WebString mimeTypeForExtension(
-      const blink::WebString& extension);
-  virtual blink::WebString wellKnownMimeTypeForExtension(
-      const blink::WebString& extension);
+      const blink::WebString& key_system) override;
+  bool supportsMediaSourceMIMEType(const blink::WebString& mime_type,
+                                   const blink::WebString& codecs) override;
+  blink::WebMimeRegistry::SupportsType supportsNonImageMIMEType(
+      const blink::WebString& mime_type) override;
+  blink::WebString mimeTypeForExtension(
+      const blink::WebString& extension) override;
+  blink::WebString wellKnownMimeTypeForExtension(
+      const blink::WebString& extension) override;
 };
 
 }  // namespace html_viewer
diff --git a/components/html_viewer/web_socket_handle_impl.h b/components/html_viewer/web_socket_handle_impl.h
index 9537d3e..fda06b00 100644
--- a/components/html_viewer/web_socket_handle_impl.h
+++ b/components/html_viewer/web_socket_handle_impl.h
@@ -28,16 +28,16 @@
  private:
   friend class WebSocketClientImpl;
 
-  virtual ~WebSocketHandleImpl();
+  ~WebSocketHandleImpl() override;
 
   // blink::WebSocketHandle methods:
-  virtual void connect(const blink::WebURL& url,
-                       const blink::WebVector<blink::WebString>& protocols,
-                       const blink::WebSecurityOrigin& origin,
-                       blink::WebSocketHandleClient*);
-  virtual void send(bool fin, MessageType, const char* data, size_t size);
-  virtual void flowControl(int64_t quota);
-  virtual void close(unsigned short code, const blink::WebString& reason);
+  void connect(const blink::WebURL& url,
+               const blink::WebVector<blink::WebString>& protocols,
+               const blink::WebSecurityOrigin& origin,
+               blink::WebSocketHandleClient*) override;
+  void send(bool fin, MessageType, const char* data, size_t size) override;
+  void flowControl(int64_t quota) override;
+  void close(unsigned short code, const blink::WebString& reason) override;
 
   // Called when we finished writing to |send_stream_|.
   void DidWriteToSendStream(bool fin,
diff --git a/components/html_viewer/web_storage_namespace_impl.h b/components/html_viewer/web_storage_namespace_impl.h
index 1c199aa..3ccb864 100644
--- a/components/html_viewer/web_storage_namespace_impl.h
+++ b/components/html_viewer/web_storage_namespace_impl.h
@@ -15,12 +15,12 @@
   WebStorageNamespaceImpl();
 
  private:
-  virtual ~WebStorageNamespaceImpl();
+  ~WebStorageNamespaceImpl() override;
 
   // blink::WebStorageNamespace methods:
-  virtual blink::WebStorageArea* createStorageArea(
-      const blink::WebString& origin);
-  virtual bool isSameNamespace(const blink::WebStorageNamespace&) const;
+  blink::WebStorageArea* createStorageArea(
+      const blink::WebString& origin) override;
+  bool isSameNamespace(const blink::WebStorageNamespace&) const override;
 
   DISALLOW_COPY_AND_ASSIGN(WebStorageNamespaceImpl);
 };
diff --git a/components/html_viewer/web_theme_engine_impl.h b/components/html_viewer/web_theme_engine_impl.h
index e146e9d..bce5501 100644
--- a/components/html_viewer/web_theme_engine_impl.h
+++ b/components/html_viewer/web_theme_engine_impl.h
@@ -12,12 +12,12 @@
 class WebThemeEngineImpl : public blink::WebThemeEngine {
  public:
   // WebThemeEngine methods:
-  virtual blink::WebSize getSize(blink::WebThemeEngine::Part);
-  virtual void paint(blink::WebCanvas* canvas,
-                     blink::WebThemeEngine::Part part,
-                     blink::WebThemeEngine::State state,
-                     const blink::WebRect& rect,
-                     const blink::WebThemeEngine::ExtraParams* extra_params);
+  blink::WebSize getSize(blink::WebThemeEngine::Part) override;
+  void paint(blink::WebCanvas* canvas,
+             blink::WebThemeEngine::Part part,
+             blink::WebThemeEngine::State state,
+             const blink::WebRect& rect,
+             const blink::WebThemeEngine::ExtraParams* extra_params) override;
   virtual void paintStateTransition(blink::WebCanvas* canvas,
                                     blink::WebThemeEngine::Part part,
                                     blink::WebThemeEngine::State startState,
diff --git a/components/html_viewer/web_url_loader_impl.h b/components/html_viewer/web_url_loader_impl.h
index a513efa..09dcf27 100644
--- a/components/html_viewer/web_url_loader_impl.h
+++ b/components/html_viewer/web_url_loader_impl.h
@@ -25,7 +25,7 @@
 class WebURLRequestExtraData : public blink::WebURLRequest::ExtraData {
  public:
   WebURLRequestExtraData();
-  virtual ~WebURLRequestExtraData();
+  ~WebURLRequestExtraData() override;
 
   mojo::URLResponsePtr synthetic_response;
 };
@@ -36,18 +36,18 @@
                             MockWebBlobRegistryImpl* web_blob_registry);
 
  private:
-  virtual ~WebURLLoaderImpl();
+  ~WebURLLoaderImpl() override;
 
   // blink::WebURLLoader methods:
-  virtual void loadSynchronously(const blink::WebURLRequest& request,
-                                 blink::WebURLResponse& response,
-                                 blink::WebURLError& error,
-                                 blink::WebData& data);
-  virtual void loadAsynchronously(const blink::WebURLRequest&,
-                                  blink::WebURLLoaderClient* client);
-  virtual void cancel();
-  virtual void setDefersLoading(bool defers_loading);
-  virtual void setLoadingTaskRunner(blink::WebTaskRunner* web_task_runner);
+  void loadSynchronously(const blink::WebURLRequest& request,
+                         blink::WebURLResponse& response,
+                         blink::WebURLError& error,
+                         blink::WebData& data) override;
+  void loadAsynchronously(const blink::WebURLRequest&,
+                          blink::WebURLLoaderClient* client) override;
+  void cancel() override;
+  void setDefersLoading(bool defers_loading) override;
+  void setLoadingTaskRunner(blink::WebTaskRunner* web_task_runner) override;
 
   void OnReceivedResponse(const blink::WebURLRequest& request,
                           mojo::URLResponsePtr response);
diff --git a/components/mus/public/cpp/BUILD.gn b/components/mus/public/cpp/BUILD.gn
index 926acb4..015040a 100644
--- a/components/mus/public/cpp/BUILD.gn
+++ b/components/mus/public/cpp/BUILD.gn
@@ -34,6 +34,7 @@
     "window_tracker.cc",
     "window_tracker.h",
     "window_tree_connection.h",
+    "window_tree_connection_observer.h",
     "window_tree_delegate.h",
     "window_tree_host_factory.h",
   ]
diff --git a/components/mus/public/cpp/lib/event_matcher.cc b/components/mus/public/cpp/lib/event_matcher.cc
index 702ad53..b619adf 100644
--- a/components/mus/public/cpp/lib/event_matcher.cc
+++ b/components/mus/public/cpp/lib/event_matcher.cc
@@ -11,6 +11,13 @@
   mojom::EventMatcherPtr matcher(mojom::EventMatcher::New());
   matcher->type_matcher = mojom::EventTypeMatcher::New();
   matcher->flags_matcher = mojom::EventFlagsMatcher::New();
+  matcher->ignore_flags_matcher = mojom::EventFlagsMatcher::New();
+  // Ignoring these makes most accelerator scenarios more straight forward. Code
+  // that needs to check them can override this setting.
+  matcher->ignore_flags_matcher->flags =
+      static_cast<mojom::EventFlags>(mojom::EVENT_FLAGS_CAPS_LOCK_DOWN |
+                                     mojom::EVENT_FLAGS_SCROLL_LOCK_DOWN |
+                                     mojom::EVENT_FLAGS_NUM_LOCK_DOWN);
   matcher->key_matcher = mojom::KeyEventMatcher::New();
 
   matcher->type_matcher->type = mus::mojom::EVENT_TYPE_KEY_PRESSED;
diff --git a/components/mus/public/cpp/lib/in_flight_change.cc b/components/mus/public/cpp/lib/in_flight_change.cc
index 002ee3f..922ae13 100644
--- a/components/mus/public/cpp/lib/in_flight_change.cc
+++ b/components/mus/public/cpp/lib/in_flight_change.cc
@@ -5,6 +5,7 @@
 #include "components/mus/public/cpp/lib/in_flight_change.h"
 
 #include "components/mus/public/cpp/lib/window_private.h"
+#include "components/mus/public/cpp/lib/window_tree_client_impl.h"
 #include "components/mus/public/cpp/window_tree_connection.h"
 
 namespace mus {
@@ -58,6 +59,41 @@
   CHECK(false);
 }
 
+// InFlightFocusChange --------------------------------------------------------
+
+InFlightFocusChange::InFlightFocusChange(WindowTreeClientImpl* connection,
+                                         Window* window)
+    : InFlightChange(nullptr, ChangeType::FOCUS),
+      connection_(connection),
+      revert_window_(nullptr) {
+  SetRevertWindow(window);
+}
+
+InFlightFocusChange::~InFlightFocusChange() {
+  SetRevertWindow(nullptr);
+}
+
+void InFlightFocusChange::SetRevertValueFrom(const InFlightChange& change) {
+  SetRevertWindow(
+      static_cast<const InFlightFocusChange&>(change).revert_window_);
+}
+
+void InFlightFocusChange::Revert() {
+  connection_->LocalSetFocus(revert_window_);
+}
+
+void InFlightFocusChange::SetRevertWindow(Window* window) {
+  if (revert_window_)
+    revert_window_->RemoveObserver(this);
+  revert_window_ = window;
+  if (revert_window_)
+    revert_window_->AddObserver(this);
+}
+
+void InFlightFocusChange::OnWindowDestroying(Window* window) {
+  SetRevertWindow(nullptr);
+}
+
 // InFlightPropertyChange -----------------------------------------------------
 
 InFlightPropertyChange::InFlightPropertyChange(
@@ -85,6 +121,26 @@
       .LocalSetSharedProperty(property_name_, revert_value_.Pass());
 }
 
+// InFlightPredefinedCursorChange ---------------------------------------------
+
+InFlightPredefinedCursorChange::InFlightPredefinedCursorChange(
+    Window* window,
+    mojom::Cursor revert_value)
+    : InFlightChange(window, ChangeType::PREDEFINED_CURSOR),
+      revert_cursor_(revert_value) {}
+
+InFlightPredefinedCursorChange::~InFlightPredefinedCursorChange() {}
+
+void InFlightPredefinedCursorChange::SetRevertValueFrom(
+    const InFlightChange& change) {
+  revert_cursor_ =
+      static_cast<const InFlightPredefinedCursorChange&>(change).revert_cursor_;
+}
+
+void InFlightPredefinedCursorChange::Revert() {
+  WindowPrivate(window()).LocalSetPredefinedCursor(revert_cursor_);
+}
+
 // InFlightVisibleChange -------------------------------------------------------
 
 InFlightVisibleChange::InFlightVisibleChange(Window* window,
diff --git a/components/mus/public/cpp/lib/in_flight_change.h b/components/mus/public/cpp/lib/in_flight_change.h
index 33d0417..54aa779 100644
--- a/components/mus/public/cpp/lib/in_flight_change.h
+++ b/components/mus/public/cpp/lib/in_flight_change.h
@@ -10,20 +10,31 @@
 
 #include "base/macros.h"
 #include "base/memory/scoped_ptr.h"
+#include "components/mus/public/cpp/window_observer.h"
 #include "mojo/public/cpp/bindings/array.h"
 #include "ui/gfx/geometry/rect.h"
 
 namespace mus {
 
+namespace mojom {
+enum Cursor : int32_t;
+}
+
 class Window;
+class WindowTreeClientImpl;
 
 enum class ChangeType {
+  ADD_CHILD,
   ADD_TRANSIENT_WINDOW,
   BOUNDS,
   DELETE_WINDOW,
+  FOCUS,
   NEW_WINDOW,
+  PREDEFINED_CURSOR,
   PROPERTY,
+  REMOVE_CHILD,
   REMOVE_TRANSIENT_WINDOW_FROM_PARENT,
+  REORDER,
   VISIBLE,
 };
 
@@ -49,11 +60,41 @@
 //   InFlightChange for the same window outstanding, then ChangeFailed() is
 //   invoked followed by Revert(). The expectation is Revert() sets the
 //   appropriate value back on the Window.
+//
+// In general there are two classes of changes:
+// 1. We are the only side allowed to make the change.
+// 2. The change can also be applied by another client. For example, the
+//    window manager may change the bounds as well as the local client.
+//
+// For (1) use CrashInFlightChange. As the name implies this change CHECKs that
+// the change succeeded. Use the following pattern for this. This code goes
+// where the change is sent to the server (in WindowTreeClientImpl):
+//   const uint32_t change_id =
+//   ScheduleInFlightChange(make_scoped_ptr(new CrashInFlightChange(
+//       window, ChangeType::REORDER)));
+//
+// For (2) use the same pattern as (1), but in the on change callback from the
+// server (e.g. OnWindowBoundsChanged()) add the following:
+//   // value_from_server is the value supplied from the server. It corresponds
+//   // to the value of the property at the time the server processed the
+//   // change. If the local change fails, this is the value reverted to.
+//   InFlightBoundsChange new_change(window, value_from_server);
+//   if (ApplyServerChangeToExistingInFlightChange(new_change)) {
+//     // There was an in flight change for the same property. The in flight
+//     // change takes the value to revert from |new_change|.
+//     return;
+//   }
+//
+//   // else case is no flight in change and the new value can be applied
+//   // immediately.
+//   WindowPrivate(window).LocalSetValue(new_value_from_server);
+//
 class InFlightChange {
  public:
   InFlightChange(Window* window, ChangeType type);
   virtual ~InFlightChange();
 
+  // NOTE: for properties not associated with any window window is null.
   Window* window() { return window_; }
   const Window* window() const { return window_; }
   ChangeType change_type() const { return change_type_; }
@@ -112,6 +153,31 @@
   DISALLOW_COPY_AND_ASSIGN(CrashInFlightChange);
 };
 
+// Focus is really a property of the WindowTreeConnection and not the Window.
+// As such, InFlightFocusChange is special in that it is not associated with
+// a particular window (InFlightFocusChange::window() returns null). Internally
+// InFlightFocusChange tracks a window to give focus to, but it may be null.
+class InFlightFocusChange : public InFlightChange, public WindowObserver {
+ public:
+  InFlightFocusChange(WindowTreeClientImpl* connection, Window* revert_window);
+  ~InFlightFocusChange() override;
+
+  // InFlightChange:
+  void SetRevertValueFrom(const InFlightChange& change) override;
+  void Revert() override;
+
+ private:
+  void SetRevertWindow(Window* window);
+
+  // WindowObserver:
+  void OnWindowDestroying(Window* window) override;
+
+  WindowTreeClientImpl* connection_;
+  Window* revert_window_;
+
+  DISALLOW_COPY_AND_ASSIGN(InFlightFocusChange);
+};
+
 class InFlightPropertyChange : public InFlightChange {
  public:
   InFlightPropertyChange(Window* window,
@@ -131,6 +197,21 @@
   DISALLOW_COPY_AND_ASSIGN(InFlightPropertyChange);
 };
 
+class InFlightPredefinedCursorChange : public InFlightChange {
+ public:
+  InFlightPredefinedCursorChange(Window* window, mojom::Cursor revert_value);
+  ~InFlightPredefinedCursorChange() override;
+
+  // InFlightChange:
+  void SetRevertValueFrom(const InFlightChange& change) override;
+  void Revert() override;
+
+ private:
+  mojom::Cursor revert_cursor_;
+
+  DISALLOW_COPY_AND_ASSIGN(InFlightPredefinedCursorChange);
+};
+
 class InFlightVisibleChange : public InFlightChange {
  public:
   InFlightVisibleChange(Window* window, const bool revert_value);
diff --git a/components/mus/public/cpp/lib/window.cc b/components/mus/public/cpp/lib/window.cc
index aa77867d..084bac5 100644
--- a/components/mus/public/cpp/lib/window.cc
+++ b/components/mus/public/cpp/lib/window.cc
@@ -192,13 +192,15 @@
   LocalSetBounds(bounds_, bounds);
 }
 
-void Window::SetClientArea(const gfx::Insets& client_area) {
+void Window::SetClientArea(
+    const gfx::Insets& client_area,
+    const std::vector<gfx::Rect>& additional_client_areas) {
   if (!OwnsWindowOrIsRoot(this))
     return;
 
   if (connection_)
-    tree_client()->SetClientArea(id_, client_area);
-  LocalSetClientArea(client_area);
+    tree_client()->SetClientArea(id_, client_area, additional_client_areas);
+  LocalSetClientArea(client_area, additional_client_areas);
 }
 
 void Window::SetVisible(bool value) {
@@ -210,6 +212,15 @@
   LocalSetVisible(value);
 }
 
+void Window::SetPredefinedCursor(mus::mojom::Cursor cursor_id) {
+  if (cursor_id_ == cursor_id)
+    return;
+
+  if (connection_)
+    tree_client()->SetPredefinedCursor(id_, cursor_id);
+  LocalSetPredefinedCursor(cursor_id);
+}
+
 bool Window::IsDrawn() const {
   if (!visible_)
     return false;
@@ -219,15 +230,15 @@
 scoped_ptr<WindowSurface> Window::RequestSurface(mojom::SurfaceType type) {
   scoped_ptr<WindowSurfaceBinding> surface_binding;
   scoped_ptr<WindowSurface> surface = WindowSurface::Create(&surface_binding);
-  AttachSurface(type, surface_binding.Pass());
+  AttachSurface(type, std::move(surface_binding));
   return surface;
 }
 
 void Window::AttachSurface(mojom::SurfaceType type,
                            scoped_ptr<WindowSurfaceBinding> surface_binding) {
-  tree_client()->AttachSurface(id_, type,
-                               surface_binding->surface_request_.Pass(),
-                               surface_binding->surface_client_.Pass());
+  tree_client()->AttachSurface(
+      id_, type, std::move(surface_binding->surface_request_),
+      mojo::MakeProxy(std::move(surface_binding->surface_client_)));
 }
 
 void Window::ClearSharedProperty(const std::string& name) {
@@ -260,7 +271,7 @@
     CHECK_EQ(child->connection(), connection_);
   LocalAddChild(child);
   if (connection_)
-    tree_client()->AddChild(child->id(), id_);
+    tree_client()->AddChild(this, child->id());
 }
 
 void Window::RemoveChild(Window* child) {
@@ -270,14 +281,14 @@
     CHECK_EQ(child->connection(), connection_);
   LocalRemoveChild(child);
   if (connection_)
-    tree_client()->RemoveChild(child->id(), id_);
+    tree_client()->RemoveChild(this, child->id());
 }
 
 void Window::Reorder(Window* relative, mojom::OrderDirection direction) {
   if (!LocalReorder(relative, direction))
     return;
   if (connection_)
-    tree_client()->Reorder(id_, relative->id(), direction);
+    tree_client()->Reorder(this, relative->id(), direction);
 }
 
 void Window::MoveToFront() {
@@ -349,8 +360,8 @@
 }
 
 void Window::SetFocus() {
-  if (connection_)
-    tree_client()->SetFocus(id_);
+  if (connection_ && IsDrawn())
+    tree_client()->SetFocus(this);
 }
 
 bool Window::HasFocus() const {
@@ -562,11 +573,17 @@
   bounds_ = new_bounds;
 }
 
-void Window::LocalSetClientArea(const gfx::Insets& new_client_area) {
+void Window::LocalSetClientArea(
+    const gfx::Insets& new_client_area,
+    const std::vector<gfx::Rect>& additional_client_areas) {
+  const std::vector<gfx::Rect> old_additional_client_areas =
+      additional_client_areas_;
   const gfx::Insets old_client_area = client_area_;
   client_area_ = new_client_area;
+  additional_client_areas_ = additional_client_areas;
   FOR_EACH_OBSERVER(WindowObserver, observers_,
-                    OnWindowClientAreaChanged(this, old_client_area));
+                    OnWindowClientAreaChanged(this, old_client_area,
+                                              old_additional_client_areas));
 }
 
 void Window::LocalSetViewportMetrics(
@@ -604,6 +621,15 @@
   NotifyWindowVisibilityChanged(this);
 }
 
+void Window::LocalSetPredefinedCursor(mojom::Cursor cursor_id) {
+  if (cursor_id_ == cursor_id)
+    return;
+
+  cursor_id_ = cursor_id;
+  FOR_EACH_OBSERVER(WindowObserver, observers_,
+                    OnWindowPredefinedCursorChanged(this, cursor_id));
+}
+
 void Window::LocalSetSharedProperty(const std::string& name,
                                     const std::vector<uint8_t>* value) {
   std::vector<uint8_t> old_value;
diff --git a/components/mus/public/cpp/lib/window_private.h b/components/mus/public/cpp/lib/window_private.h
index 930ffb3c..d1bec3f3 100644
--- a/components/mus/public/cpp/lib/window_private.h
+++ b/components/mus/public/cpp/lib/window_private.h
@@ -5,6 +5,8 @@
 #ifndef COMPONENTS_MUS_PUBLIC_CPP_LIB_WINDOW_PRIVATE_H_
 #define COMPONENTS_MUS_PUBLIC_CPP_LIB_WINDOW_PRIVATE_H_
 
+#include <vector>
+
 #include "components/mus/public/cpp/window.h"
 #include "mojo/public/cpp/bindings/array.h"
 
@@ -63,11 +65,16 @@
                       const gfx::Rect& new_bounds) {
     window_->LocalSetBounds(old_bounds, new_bounds);
   }
-  void LocalSetClientArea(const gfx::Insets& new_client_area) {
-    window_->LocalSetClientArea(new_client_area);
+  void LocalSetClientArea(
+      const gfx::Insets& client_area,
+      const std::vector<gfx::Rect>& additional_client_areas) {
+    window_->LocalSetClientArea(client_area, additional_client_areas);
   }
   void LocalSetDrawn(bool drawn) { window_->LocalSetDrawn(drawn); }
   void LocalSetVisible(bool visible) { window_->LocalSetVisible(visible); }
+  void LocalSetPredefinedCursor(mojom::Cursor cursor) {
+    window_->LocalSetPredefinedCursor(cursor);
+  }
   void LocalSetSharedProperty(const std::string& name,
                               mojo::Array<uint8_t> new_data);
   void LocalSetSharedProperty(const std::string& name,
diff --git a/components/mus/public/cpp/lib/window_surface.cc b/components/mus/public/cpp/lib/window_surface.cc
index 076243c..746d31c 100644
--- a/components/mus/public/cpp/lib/window_surface.cc
+++ b/components/mus/public/cpp/lib/window_surface.cc
@@ -17,10 +17,10 @@
   mojo::InterfaceRequest<mojom::SurfaceClient> surface_client_request =
       GetProxy(&surface_client);
 
-  surface_binding->reset(
-      new WindowSurfaceBinding(GetProxy(&surface), surface_client.Pass()));
+  surface_binding->reset(new WindowSurfaceBinding(
+      GetProxy(&surface), surface_client.PassInterface()));
   return make_scoped_ptr(new WindowSurface(surface.PassInterface(),
-                                           surface_client_request.Pass()));
+                                           std::move(surface_client_request)));
 }
 
 WindowSurface::~WindowSurface() {}
@@ -28,9 +28,9 @@
 void WindowSurface::BindToThread() {
   DCHECK(!thread_checker_);
   thread_checker_.reset(new base::ThreadChecker());
-  surface_.Bind(surface_info_.Pass());
-  client_binding_.reset(
-      new mojo::Binding<mojom::SurfaceClient>(this, client_request_.Pass()));
+  surface_.Bind(std::move(surface_info_));
+  client_binding_.reset(new mojo::Binding<mojom::SurfaceClient>(
+      this, std::move(client_request_)));
 }
 
 void WindowSurface::SubmitCompositorFrame(mojom::CompositorFramePtr frame,
@@ -39,15 +39,15 @@
   DCHECK(thread_checker_->CalledOnValidThread());
   if (!surface_)
     return;
-  surface_->SubmitCompositorFrame(frame.Pass(), callback);
+  surface_->SubmitCompositorFrame(std::move(frame), callback);
 }
 
 WindowSurface::WindowSurface(
     mojo::InterfacePtrInfo<mojom::Surface> surface_info,
     mojo::InterfaceRequest<mojom::SurfaceClient> client_request)
     : client_(nullptr),
-      surface_info_(surface_info.Pass()),
-      client_request_(client_request.Pass()) {}
+      surface_info_(std::move(surface_info)),
+      client_request_(std::move(client_request)) {}
 
 void WindowSurface::ReturnResources(
     mojo::Array<mojom::ReturnedResourcePtr> resources) {
@@ -55,15 +55,15 @@
   DCHECK(thread_checker_->CalledOnValidThread());
   if (!client_)
     return;
-  client_->OnResourcesReturned(this, resources.Pass());
+  client_->OnResourcesReturned(this, std::move(resources));
 }
 
 WindowSurfaceBinding::~WindowSurfaceBinding() {}
 
 WindowSurfaceBinding::WindowSurfaceBinding(
     mojo::InterfaceRequest<mojom::Surface> surface_request,
-    mojom::SurfaceClientPtr surface_client)
-    : surface_request_(surface_request.Pass()),
-      surface_client_(surface_client.Pass()) {}
+    mojo::InterfacePtrInfo<mojom::SurfaceClient> surface_client)
+    : surface_request_(std::move(surface_request)),
+      surface_client_(std::move(surface_client)) {}
 
 }  // namespace mus
diff --git a/components/mus/public/cpp/lib/window_tree_client_impl.cc b/components/mus/public/cpp/lib/window_tree_client_impl.cc
index 2b094e9..570c9b5b 100644
--- a/components/mus/public/cpp/lib/window_tree_client_impl.cc
+++ b/components/mus/public/cpp/lib/window_tree_client_impl.cc
@@ -11,6 +11,7 @@
 #include "components/mus/public/cpp/window_manager_delegate.h"
 #include "components/mus/public/cpp/window_observer.h"
 #include "components/mus/public/cpp/window_tree_connection.h"
+#include "components/mus/public/cpp/window_tree_connection_observer.h"
 #include "components/mus/public/cpp/window_tree_delegate.h"
 #include "mojo/application/public/cpp/application_impl.h"
 #include "mojo/application/public/cpp/connect.h"
@@ -157,14 +158,18 @@
   tree_->DeleteWindow(change_id, window->id());
 }
 
-void WindowTreeClientImpl::AddChild(Id child_id, Id parent_id) {
+void WindowTreeClientImpl::AddChild(Window* parent, Id child_id) {
   DCHECK(tree_);
-  tree_->AddWindow(parent_id, child_id, ActionCompletedCallback());
+  const uint32_t change_id = ScheduleInFlightChange(
+      make_scoped_ptr(new CrashInFlightChange(parent, ChangeType::ADD_CHILD)));
+  tree_->AddWindow(change_id, parent->id(), child_id);
 }
 
-void WindowTreeClientImpl::RemoveChild(Id child_id, Id parent_id) {
+void WindowTreeClientImpl::RemoveChild(Window* parent, Id child_id) {
   DCHECK(tree_);
-  tree_->RemoveWindowFromParent(child_id, ActionCompletedCallback());
+  const uint32_t change_id = ScheduleInFlightChange(make_scoped_ptr(
+      new CrashInFlightChange(parent, ChangeType::REMOVE_CHILD)));
+  tree_->RemoveWindowFromParent(change_id, child_id);
 }
 
 void WindowTreeClientImpl::AddTransientWindow(Window* window,
@@ -183,12 +188,13 @@
   tree_->RemoveTransientWindowFromParent(change_id, window->id());
 }
 
-void WindowTreeClientImpl::Reorder(Id window_id,
+void WindowTreeClientImpl::Reorder(Window* window,
                                    Id relative_window_id,
                                    mojom::OrderDirection direction) {
   DCHECK(tree_);
-  tree_->ReorderWindow(window_id, relative_window_id, direction,
-                       ActionCompletedCallback());
+  const uint32_t change_id = ScheduleInFlightChange(
+      make_scoped_ptr(new CrashInFlightChange(window, ChangeType::REORDER)));
+  tree_->ReorderWindow(change_id, window->id(), relative_window_id, direction);
 }
 
 bool WindowTreeClientImpl::OwnsWindow(Id id) const {
@@ -204,17 +210,24 @@
   tree_->SetWindowBounds(change_id, window->id(), mojo::Rect::From(bounds));
 }
 
-void WindowTreeClientImpl::SetClientArea(Id window_id,
-                                         const gfx::Insets& client_area) {
+void WindowTreeClientImpl::SetClientArea(
+    Id window_id,
+    const gfx::Insets& client_area,
+    const std::vector<gfx::Rect>& additional_client_areas) {
   DCHECK(tree_);
-  tree_->SetClientArea(window_id, mojo::Insets::From(client_area));
+  tree_->SetClientArea(
+      window_id, mojo::Insets::From(client_area),
+      mojo::Array<mojo::RectPtr>::From(additional_client_areas));
 }
 
-void WindowTreeClientImpl::SetFocus(Id window_id) {
+void WindowTreeClientImpl::SetFocus(Window* window) {
   // In order for us to get here we had to have exposed a window, which implies
   // we got a connection.
   DCHECK(tree_);
-  tree_->SetFocus(window_id);
+  const uint32_t change_id = ScheduleInFlightChange(
+      make_scoped_ptr(new InFlightFocusChange(this, focused_window_)));
+  tree_->SetFocus(change_id, window ? window->id() : 0);
+  LocalSetFocus(window);
 }
 
 void WindowTreeClientImpl::SetCanFocus(Id window_id, bool can_focus) {
@@ -222,6 +235,20 @@
   tree_->SetCanFocus(window_id, can_focus);
 }
 
+void WindowTreeClientImpl::SetPredefinedCursor(Id window_id,
+                                               mus::mojom::Cursor cursor_id) {
+  DCHECK(tree_);
+
+  Window* window = GetWindowById(window_id);
+  if (!window)
+    return;
+
+  // We make an inflight change thing here.
+  const uint32_t change_id = ScheduleInFlightChange(make_scoped_ptr(
+      new InFlightPredefinedCursorChange(window, window->predefined_cursor())));
+  tree_->SetPredefinedCursor(change_id, window_id, cursor_id);
+}
+
 void WindowTreeClientImpl::SetVisible(Window* window, bool visible) {
   DCHECK(tree_);
   const uint32_t change_id = ScheduleInFlightChange(
@@ -276,14 +303,37 @@
   tree_->AttachSurface(window_id, type, surface.Pass(), client.Pass());
 }
 
+void WindowTreeClientImpl::LocalSetFocus(Window* focused) {
+  Window* blurred = focused_window_;
+  // Update |focused_window_| before calling any of the observers, so that the
+  // observers get the correct result from calling |Window::HasFocus()|,
+  // |WindowTreeConnection::GetFocusedWindow()| etc.
+  focused_window_ = focused;
+  if (blurred) {
+    FOR_EACH_OBSERVER(WindowObserver, *WindowPrivate(blurred).observers(),
+                      OnWindowFocusChanged(focused, blurred));
+  }
+  if (focused) {
+    FOR_EACH_OBSERVER(WindowObserver, *WindowPrivate(focused).observers(),
+                      OnWindowFocusChanged(focused, blurred));
+  }
+  FOR_EACH_OBSERVER(WindowTreeConnectionObserver, observers_,
+                    OnWindowTreeFocusChanged(focused, blurred));
+}
+
 void WindowTreeClientImpl::AddWindow(Window* window) {
   DCHECK(windows_.find(window->id()) == windows_.end());
   windows_[window->id()] = window;
 }
 
 void WindowTreeClientImpl::RemoveWindow(Id window_id) {
-  if (focused_window_ && focused_window_->id() == window_id)
-    OnWindowFocused(0);
+  if (focused_window_ && focused_window_->id() == window_id) {
+    // The focused window is being removed. When this happens the server
+    // advances focus. We don't want to randomly pick a Window to get focus, so
+    // we update local state only, and wait for the next focus change from the
+    // server.
+    LocalSetFocus(nullptr);
+  }
 
   IdToWindowMap::iterator it = windows_.find(window_id);
   if (it != windows_.end())
@@ -292,7 +342,7 @@
   // Remove any InFlightChanges associated with the window.
   std::set<uint32_t> in_flight_change_ids;
   for (const auto& pair : in_flight_map_) {
-    if (pair.second->window()->id() == window_id)
+    if (pair.second->window() && pair.second->window()->id() == window_id)
       in_flight_change_ids.insert(pair.first);
   }
   for (auto change_id : in_flight_change_ids)
@@ -353,6 +403,11 @@
   focused_window_ = GetWindowById(focused_window_id);
 
   delegate_->OnEmbed(root_);
+
+  if (focused_window_) {
+    FOR_EACH_OBSERVER(WindowTreeConnectionObserver, observers_,
+                      OnWindowTreeFocusChanged(focused_window_, nullptr));
+  }
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -402,6 +457,15 @@
 ////////////////////////////////////////////////////////////////////////////////
 // WindowTreeClientImpl, WindowTreeClient implementation:
 
+void WindowTreeClientImpl::AddObserver(WindowTreeConnectionObserver* observer) {
+  observers_.AddObserver(observer);
+}
+
+void WindowTreeClientImpl::RemoveObserver(
+    WindowTreeConnectionObserver* observer) {
+  observers_.RemoveObserver(observer);
+}
+
 void WindowTreeClientImpl::OnEmbed(ConnectionSpecificId connection_id,
                                    mojom::WindowDataPtr root_data,
                                    mojom::WindowTreePtr tree,
@@ -445,11 +509,14 @@
 
 void WindowTreeClientImpl::OnClientAreaChanged(
     uint32_t window_id,
-    mojo::InsetsPtr old_client_area,
-    mojo::InsetsPtr new_client_area) {
+    mojo::InsetsPtr new_client_area,
+    mojo::Array<mojo::RectPtr> new_additional_client_areas) {
   Window* window = GetWindowById(window_id);
-  if (window)
-    WindowPrivate(window).LocalSetClientArea(new_client_area.To<gfx::Insets>());
+  if (window) {
+    WindowPrivate(window).LocalSetClientArea(
+        new_client_area.To<gfx::Insets>(),
+        new_additional_client_areas.To<std::vector<gfx::Rect>>());
+  }
 }
 
 void WindowTreeClientImpl::OnTransientWindowAdded(
@@ -581,20 +648,26 @@
 }
 
 void WindowTreeClientImpl::OnWindowFocused(Id focused_window_id) {
-  Window* focused = GetWindowById(focused_window_id);
-  Window* blurred = focused_window_;
-  // Update |focused_window_| before calling any of the observers, so that the
-  // observers get the correct result from calling |Window::HasFocus()|,
-  // |WindowTreeConnection::GetFocusedWindow()| etc.
-  focused_window_ = focused;
-  if (blurred) {
-    FOR_EACH_OBSERVER(WindowObserver, *WindowPrivate(blurred).observers(),
-                      OnWindowFocusChanged(focused, blurred));
-  }
-  if (focused) {
-    FOR_EACH_OBSERVER(WindowObserver, *WindowPrivate(focused).observers(),
-                      OnWindowFocusChanged(focused, blurred));
-  }
+  Window* focused_window = GetWindowById(focused_window_id);
+  InFlightFocusChange new_change(this, focused_window);
+  if (ApplyServerChangeToExistingInFlightChange(new_change))
+    return;
+
+  LocalSetFocus(focused_window);
+}
+
+void WindowTreeClientImpl::OnWindowPredefinedCursorChanged(
+    Id window_id,
+    mojom::Cursor cursor) {
+  Window* window = GetWindowById(window_id);
+  if (!window)
+    return;
+
+  InFlightPredefinedCursorChange new_change(window, cursor);
+  if (ApplyServerChangeToExistingInFlightChange(new_change))
+    return;
+
+  WindowPrivate(window).LocalSetPredefinedCursor(cursor);
 }
 
 void WindowTreeClientImpl::OnChangeCompleted(uint32 change_id, bool success) {
diff --git a/components/mus/public/cpp/lib/window_tree_client_impl.h b/components/mus/public/cpp/lib/window_tree_client_impl.h
index af224db..7e46a79a 100644
--- a/components/mus/public/cpp/lib/window_tree_client_impl.h
+++ b/components/mus/public/cpp/lib/window_tree_client_impl.h
@@ -7,6 +7,7 @@
 
 #include <map>
 
+#include "base/observer_list.h"
 #include "components/mus/common/types.h"
 #include "components/mus/public/cpp/window.h"
 #include "components/mus/public/cpp/window_tree_connection.h"
@@ -48,13 +49,13 @@
   // These methods take TransportIds. For windows owned by the current
   // connection, the connection id high word can be zero. In all cases, the
   // TransportId 0x1 refers to the root window.
-  void AddChild(Id child_id, Id parent_id);
-  void RemoveChild(Id child_id, Id parent_id);
+  void AddChild(Window* parent, Id child_id);
+  void RemoveChild(Window* parent, Id child_id);
 
   void AddTransientWindow(Window* window, Id transient_window_id);
   void RemoveTransientWindowFromParent(Window* window);
 
-  void Reorder(Id window_id,
+  void Reorder(Window* window,
                Id relative_window_id,
                mojom::OrderDirection direction);
 
@@ -64,9 +65,12 @@
   void SetBounds(Window* window,
                  const gfx::Rect& old_bounds,
                  const gfx::Rect& bounds);
-  void SetClientArea(Id window_id, const gfx::Insets& client_area);
-  void SetFocus(Id window_id);
+  void SetClientArea(Id window_id,
+                     const gfx::Insets& client_area,
+                     const std::vector<gfx::Rect>& additional_client_areas);
+  void SetFocus(Window* window);
   void SetCanFocus(Id window_id, bool can_focus);
+  void SetPredefinedCursor(Id window_id, mus::mojom::Cursor cursor_id);
   void SetVisible(Window* window, bool visible);
   void SetProperty(Window* window,
                    const std::string& name,
@@ -86,6 +90,9 @@
                      mojo::InterfaceRequest<mojom::Surface> surface,
                      mojom::SurfaceClientPtr client);
 
+  // Sets focus to |window| without notifying the server.
+  void LocalSetFocus(Window* window);
+
   // Start/stop tracking windows. While tracked, they can be retrieved via
   // WindowTreeConnection::GetWindowById.
   void AddWindow(Window* window);
@@ -108,11 +115,13 @@
   // Returns the oldest InFlightChange that matches |change|.
   InFlightChange* GetOldestInFlightChangeMatching(const InFlightChange& change);
 
+  // See InFlightChange for details on how InFlightChanges are used.
   uint32_t ScheduleInFlightChange(scoped_ptr<InFlightChange> change);
 
   // Returns true if there is an InFlightChange that matches |change|. If there
   // is an existing change SetRevertValueFrom() is invoked on it. Returns false
   // if there is no InFlightChange matching |change|.
+  // See InFlightChange for details on how InFlightChanges are used.
   bool ApplyServerChangeToExistingInFlightChange(const InFlightChange& change);
 
   // OnEmbed() calls into this. Exposed as a separate function for testing.
@@ -129,6 +138,8 @@
   Window* NewWindow(const Window::SharedProperties* properties) override;
   bool IsEmbedRoot() override;
   ConnectionSpecificId GetConnectionId() override;
+  void AddObserver(WindowTreeConnectionObserver* observer) override;
+  void RemoveObserver(WindowTreeConnectionObserver* observer) override;
 
   // Overridden from WindowTreeClient:
   void OnEmbed(ConnectionSpecificId connection_id,
@@ -141,9 +152,10 @@
   void OnWindowBoundsChanged(Id window_id,
                              mojo::RectPtr old_bounds,
                              mojo::RectPtr new_bounds) override;
-  void OnClientAreaChanged(uint32_t window_id,
-                           mojo::InsetsPtr old_client_area,
-                           mojo::InsetsPtr new_client_area) override;
+  void OnClientAreaChanged(
+      uint32_t window_id,
+      mojo::InsetsPtr new_client_area,
+      mojo::Array<mojo::RectPtr> new_additional_client_areas) override;
   void OnTransientWindowAdded(uint32_t window_id,
                               uint32_t transient_window_id) override;
   void OnTransientWindowRemoved(uint32_t window_id,
@@ -169,6 +181,8 @@
                           Id window_id,
                           mojom::EventPtr event) override;
   void OnWindowFocused(Id focused_window_id) override;
+  void OnWindowPredefinedCursorChanged(Id window_id,
+                                       mojom::Cursor cursor) override;
   void OnChangeCompleted(uint32_t change_id, bool success) override;
   void WmSetBounds(uint32_t change_id,
                    Id window_id,
@@ -211,6 +225,8 @@
 
   bool in_destructor_;
 
+  base::ObserverList<WindowTreeConnectionObserver> observers_;
+
   MOJO_DISALLOW_COPY_AND_ASSIGN(WindowTreeClientImpl);
 };
 
diff --git a/components/mus/public/cpp/tests/test_window_tree.cc b/components/mus/public/cpp/tests/test_window_tree.cc
index 1eff074..1d70f32f 100644
--- a/components/mus/public/cpp/tests/test_window_tree.cc
+++ b/components/mus/public/cpp/tests/test_window_tree.cc
@@ -34,8 +34,10 @@
   change_id_ = change_id;
 }
 
-void TestWindowTree::SetClientArea(uint32_t window_id, mojo::InsetsPtr insets) {
-}
+void TestWindowTree::SetClientArea(
+    uint32_t window_id,
+    mojo::InsetsPtr insets,
+    mojo::Array<mojo::RectPtr> additional_client_areas) {}
 
 void TestWindowTree::SetWindowVisibility(uint32_t change_id,
                                          uint32_t window_id,
@@ -58,13 +60,12 @@
     mojo::InterfaceRequest<mojom::Surface> surface,
     mojom::SurfaceClientPtr client) {}
 
-void TestWindowTree::AddWindow(uint32_t parent,
-                               uint32_t child,
-                               const AddWindowCallback& callback) {}
+void TestWindowTree::AddWindow(uint32_t change_id,
+                               uint32_t parent,
+                               uint32_t child) {}
 
-void TestWindowTree::RemoveWindowFromParent(
-    uint32_t window_id,
-    const RemoveWindowFromParentCallback& callback) {}
+void TestWindowTree::RemoveWindowFromParent(uint32_t change_id,
+                                            uint32_t window_id) {}
 
 void TestWindowTree::AddTransientWindow(uint32_t change_id,
                                         uint32_t window_id,
@@ -74,10 +75,10 @@
     uint32_t change_id,
     uint32_t transient_window_id) {}
 
-void TestWindowTree::ReorderWindow(uint32_t window_id,
+void TestWindowTree::ReorderWindow(uint32_t change_id,
+                                   uint32_t window_id,
                                    uint32_t relative_window_id,
-                                   mojom::OrderDirection direction,
-                                   const ReorderWindowCallback& callback) {}
+                                   mojom::OrderDirection direction) {}
 
 void TestWindowTree::GetWindowTree(uint32_t window_id,
                                    const GetWindowTreeCallback& callback) {}
@@ -87,10 +88,17 @@
                            uint32_t policy_bitmask,
                            const EmbedCallback& callback) {}
 
-void TestWindowTree::SetFocus(uint32_t window_id) {}
+void TestWindowTree::SetFocus(uint32_t change_id, uint32_t window_id) {
+  got_change_ = true;
+  change_id_ = change_id;
+}
 
 void TestWindowTree::SetCanFocus(uint32_t window_id, bool can_focus) {}
 
+void TestWindowTree::SetPredefinedCursor(uint32_t change_id,
+                                         uint32_t window_id,
+                                         mus::mojom::Cursor cursor_id) {}
+
 void TestWindowTree::SetWindowTextInputState(uint32_t window_id,
                                              mojo::TextInputStatePtr state) {}
 
diff --git a/components/mus/public/cpp/tests/test_window_tree.h b/components/mus/public/cpp/tests/test_window_tree.h
index 80bdec5..8a35699 100644
--- a/components/mus/public/cpp/tests/test_window_tree.h
+++ b/components/mus/public/cpp/tests/test_window_tree.h
@@ -31,7 +31,10 @@
   void SetWindowBounds(uint32_t change_id,
                        uint32_t window_id,
                        mojo::RectPtr bounds) override;
-  void SetClientArea(uint32_t window_id, mojo::InsetsPtr insets) override;
+  void SetClientArea(
+      uint32_t window_id,
+      mojo::InsetsPtr insets,
+      mojo::Array<mojo::RectPtr> additional_client_areas) override;
   void SetWindowVisibility(uint32_t change_id,
                            uint32_t window_id,
                            bool visible) override;
@@ -43,29 +46,28 @@
                      mojom::SurfaceType type,
                      mojo::InterfaceRequest<mojom::Surface> surface,
                      mojom::SurfaceClientPtr client) override;
-  void AddWindow(uint32_t parent,
-                 uint32_t child,
-                 const AddWindowCallback& callback) override;
-  void RemoveWindowFromParent(
-      uint32_t window_id,
-      const RemoveWindowFromParentCallback& callback) override;
+  void AddWindow(uint32_t change_id, uint32_t parent, uint32_t child) override;
+  void RemoveWindowFromParent(uint32_t change_id, uint32_t window_id) override;
   void AddTransientWindow(uint32_t change_id,
                           uint32_t window_id,
                           uint32_t transient_window_id) override;
   void RemoveTransientWindowFromParent(uint32_t change_id,
                                        uint32_t window_id) override;
-  void ReorderWindow(uint32_t window_id,
+  void ReorderWindow(uint32_t change_id,
+                     uint32_t window_id,
                      uint32_t relative_window_id,
-                     mojom::OrderDirection direction,
-                     const ReorderWindowCallback& callback) override;
+                     mojom::OrderDirection direction) override;
   void GetWindowTree(uint32_t window_id,
                      const GetWindowTreeCallback& callback) override;
   void Embed(uint32_t window_id,
              mojom::WindowTreeClientPtr client,
              uint32_t policy_bitmask,
              const EmbedCallback& callback) override;
-  void SetFocus(uint32_t window_id) override;
+  void SetFocus(uint32_t change_id, uint32_t window_id) override;
   void SetCanFocus(uint32_t window_id, bool can_focus) override;
+  void SetPredefinedCursor(uint32_t change_id,
+                           uint32_t window_id,
+                           mus::mojom::Cursor cursor_id) override;
   void SetWindowTextInputState(uint32_t window_id,
                                mojo::TextInputStatePtr state) override;
   void SetImeVisibility(uint32_t window_id,
diff --git a/components/mus/public/cpp/tests/window_tree_client_impl_unittest.cc b/components/mus/public/cpp/tests/window_tree_client_impl_unittest.cc
index 11f54962..5c61a40 100644
--- a/components/mus/public/cpp/tests/window_tree_client_impl_unittest.cc
+++ b/components/mus/public/cpp/tests/window_tree_client_impl_unittest.cc
@@ -276,4 +276,97 @@
   EXPECT_EQ(original_visible, root->visible());
 }
 
+// Verifies focus is reverted if the server replied that the change failed.
+TEST_F(WindowTreeClientImplTest, SetFocusFailed) {
+  WindowTreeSetup setup;
+  Window* root = setup.window_tree_connection()->GetRoot();
+  ASSERT_TRUE(root);
+  root->SetVisible(true);
+  Window* child = setup.window_tree_connection()->NewWindow();
+  child->SetVisible(true);
+  root->AddChild(child);
+  Window* original_focus = setup.window_tree_connection()->GetFocusedWindow();
+  Window* new_focus = child;
+  ASSERT_NE(new_focus, original_focus);
+  new_focus->SetFocus();
+  ASSERT_TRUE(new_focus->HasFocus());
+  uint32_t change_id;
+  ASSERT_TRUE(setup.window_tree()->GetAndClearChangeId(&change_id));
+  setup.window_tree_client()->OnChangeCompleted(change_id, false);
+  EXPECT_EQ(original_focus, setup.window_tree_connection()->GetFocusedWindow());
+}
+
+// Simulates a focus change, and while the focus change is in flight the server
+// replies with a new focus and the original focus change fails.
+TEST_F(WindowTreeClientImplTest, SetFocusFailedWithPendingChange) {
+  WindowTreeSetup setup;
+  Window* root = setup.window_tree_connection()->GetRoot();
+  ASSERT_TRUE(root);
+  root->SetVisible(true);
+  Window* child1 = setup.window_tree_connection()->NewWindow();
+  child1->SetVisible(true);
+  root->AddChild(child1);
+  Window* child2 = setup.window_tree_connection()->NewWindow();
+  child2->SetVisible(true);
+  root->AddChild(child2);
+  Window* original_focus = setup.window_tree_connection()->GetFocusedWindow();
+  Window* new_focus = child1;
+  ASSERT_NE(new_focus, original_focus);
+  new_focus->SetFocus();
+  ASSERT_TRUE(new_focus->HasFocus());
+  uint32_t change_id;
+  ASSERT_TRUE(setup.window_tree()->GetAndClearChangeId(&change_id));
+
+  // Simulate the server responding with a focus change.
+  setup.window_tree_client()->OnWindowFocused(child2->id());
+
+  // This shouldn't trigger focus changing yet.
+  EXPECT_TRUE(child1->HasFocus());
+
+  // Tell the client the change failed, which should trigger failing to the
+  // most recent focus from server.
+  setup.window_tree_client()->OnChangeCompleted(change_id, false);
+  EXPECT_FALSE(child1->HasFocus());
+  EXPECT_TRUE(child2->HasFocus());
+  EXPECT_EQ(child2, setup.window_tree_connection()->GetFocusedWindow());
+
+  // Simulate server changing focus to child1. Should take immediately.
+  setup.window_tree_client()->OnWindowFocused(child1->id());
+  EXPECT_TRUE(child1->HasFocus());
+}
+
+TEST_F(WindowTreeClientImplTest, FocusOnRemovedWindowWithInFlightFocusChange) {
+  WindowTreeSetup setup;
+  Window* root = setup.window_tree_connection()->GetRoot();
+  ASSERT_TRUE(root);
+  root->SetVisible(true);
+  Window* child1 = setup.window_tree_connection()->NewWindow();
+  child1->SetVisible(true);
+  root->AddChild(child1);
+  Window* child2 = setup.window_tree_connection()->NewWindow();
+  child2->SetVisible(true);
+  root->AddChild(child2);
+
+  child1->SetFocus();
+  uint32_t change_id;
+  ASSERT_TRUE(setup.window_tree()->GetAndClearChangeId(&change_id));
+
+  // Destroy child1, which should set focus to null.
+  child1->Destroy();
+  EXPECT_EQ(nullptr, setup.window_tree_connection()->GetFocusedWindow());
+
+  // Server changes focus to 2.
+  setup.window_tree_client()->OnWindowFocused(child2->id());
+  // Shouldn't take immediately.
+  EXPECT_FALSE(child2->HasFocus());
+
+  // Ack the change, focus should still be null.
+  setup.window_tree_client()->OnChangeCompleted(change_id, true);
+  EXPECT_EQ(nullptr, setup.window_tree_connection()->GetFocusedWindow());
+
+  // Change to 2 again, this time it should take.
+  setup.window_tree_client()->OnWindowFocused(child2->id());
+  EXPECT_TRUE(child2->HasFocus());
+}
+
 }  // namespace mus
diff --git a/components/mus/public/cpp/window.h b/components/mus/public/cpp/window.h
index 9da43ce..8005cf4 100644
--- a/components/mus/public/cpp/window.h
+++ b/components/mus/public/cpp/window.h
@@ -72,12 +72,23 @@
   void SetBounds(const gfx::Rect& bounds);
 
   const gfx::Insets& client_area() const { return client_area_; }
-  void SetClientArea(const gfx::Insets& new_client_area);
+  const std::vector<gfx::Rect>& additional_client_areas() {
+    return additional_client_areas_;
+  }
+  void SetClientArea(const gfx::Insets& new_client_area) {
+    SetClientArea(new_client_area, std::vector<gfx::Rect>());
+  }
+  void SetClientArea(const gfx::Insets& new_client_area,
+                     const std::vector<gfx::Rect>& additional_client_areas);
 
   // Visibility (also see IsDrawn()). When created windows are hidden.
   bool visible() const { return visible_; }
   void SetVisible(bool value);
 
+  // Cursors
+  mojom::Cursor predefined_cursor() const { return cursor_id_; }
+  void SetPredefinedCursor(mus::mojom::Cursor cursor_id);
+
   // A Window is drawn if the Window and all its ancestors are visible and the
   // Window is attached to the root.
   bool IsDrawn() const;
@@ -219,11 +230,14 @@
   // Returns true if the order actually changed.
   bool LocalReorder(Window* relative, mojom::OrderDirection direction);
   void LocalSetBounds(const gfx::Rect& old_bounds, const gfx::Rect& new_bounds);
-  void LocalSetClientArea(const gfx::Insets& new_client_area);
+  void LocalSetClientArea(
+      const gfx::Insets& new_client_area,
+      const std::vector<gfx::Rect>& additional_client_areas);
   void LocalSetViewportMetrics(const mojom::ViewportMetrics& old_metrics,
                                const mojom::ViewportMetrics& new_metrics);
   void LocalSetDrawn(bool drawn);
   void LocalSetVisible(bool visible);
+  void LocalSetPredefinedCursor(mojom::Cursor cursor_id);
   void LocalSetSharedProperty(const std::string& name,
                               const std::vector<uint8_t>* data);
 
@@ -271,11 +285,14 @@
 
   gfx::Rect bounds_;
   gfx::Insets client_area_;
+  std::vector<gfx::Rect> additional_client_areas_;
 
   mojom::ViewportMetricsPtr viewport_metrics_;
 
   bool visible_;
 
+  mojom::Cursor cursor_id_;
+
   SharedProperties properties_;
 
   // Drawn state is derived from the visible state and the parent's visible
diff --git a/components/mus/public/cpp/window_observer.h b/components/mus/public/cpp/window_observer.h
index 979428ad..b0b3597 100644
--- a/components/mus/public/cpp/window_observer.h
+++ b/components/mus/public/cpp/window_observer.h
@@ -22,8 +22,7 @@
 // If the change originated from another connection to the window manager, it's
 // possible that the change has already been applied to the service-side model
 // prior to being called, so for example in the case of OnWindowDestroying(),
-// it's
-// possible the window has already been destroyed on the service side.
+// it's possible the window has already been destroyed on the service side.
 
 class WindowObserver {
  public:
@@ -54,8 +53,10 @@
   virtual void OnWindowBoundsChanged(Window* window,
                                      const gfx::Rect& old_bounds,
                                      const gfx::Rect& new_bounds) {}
-  virtual void OnWindowClientAreaChanged(Window* window,
-                                         const gfx::Insets& old_client_area) {}
+  virtual void OnWindowClientAreaChanged(
+      Window* window,
+      const gfx::Insets& old_client_area,
+      const std::vector<gfx::Rect>& old_additional_client_areas) {}
 
   virtual void OnWindowViewportMetricsChanged(
       Window* window,
@@ -64,6 +65,9 @@
 
   virtual void OnWindowFocusChanged(Window* gained_focus, Window* lost_focus) {}
 
+  virtual void OnWindowPredefinedCursorChanged(Window* window,
+                                               mojom::Cursor cursor) {}
+
   virtual void OnWindowInputEvent(Window* window,
                                   const mojom::EventPtr& event) {}
 
diff --git a/components/mus/public/cpp/window_surface.h b/components/mus/public/cpp/window_surface.h
index 2a285259..ae15193a3 100644
--- a/components/mus/public/cpp/window_surface.h
+++ b/components/mus/public/cpp/window_surface.h
@@ -69,11 +69,12 @@
   friend class WindowSurface;
   friend class Window;
 
-  WindowSurfaceBinding(mojo::InterfaceRequest<mojom::Surface> surface_request,
-                       mojom::SurfaceClientPtr surface_client);
+  WindowSurfaceBinding(
+      mojo::InterfaceRequest<mojom::Surface> surface_request,
+      mojo::InterfacePtrInfo<mojom::SurfaceClient> surface_client);
 
   mojo::InterfaceRequest<mojom::Surface> surface_request_;
-  mojom::SurfaceClientPtr surface_client_;
+  mojo::InterfacePtrInfo<mojom::SurfaceClient> surface_client_;
 
   DISALLOW_COPY_AND_ASSIGN(WindowSurfaceBinding);
 };
diff --git a/components/mus/public/cpp/window_tree_connection.h b/components/mus/public/cpp/window_tree_connection.h
index fc5b7db..61897fa 100644
--- a/components/mus/public/cpp/window_tree_connection.h
+++ b/components/mus/public/cpp/window_tree_connection.h
@@ -17,6 +17,7 @@
 
 class Window;
 class WindowManagerDelegate;
+class WindowTreeConnectionObserver;
 class WindowTreeDelegate;
 
 // Encapsulates a connection to a window tree. A unique connection is made
@@ -67,6 +68,9 @@
 
   // Returns the id for this connection.
   virtual ConnectionSpecificId GetConnectionId() = 0;
+
+  virtual void AddObserver(WindowTreeConnectionObserver* observer) = 0;
+  virtual void RemoveObserver(WindowTreeConnectionObserver* observer) = 0;
 };
 
 }  // namespace mus
diff --git a/components/mus/public/cpp/window_tree_connection_observer.h b/components/mus/public/cpp/window_tree_connection_observer.h
new file mode 100644
index 0000000..b29d71c
--- /dev/null
+++ b/components/mus/public/cpp/window_tree_connection_observer.h
@@ -0,0 +1,23 @@
+// 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.
+
+#ifndef COMPONENTS_MUS_PUBLIC_CPP_WINDOW_TREE_CONNECTION_OBSERVER_H_
+#define COMPONENTS_MUS_PUBLIC_CPP_WINDOW_TREE_CONNECTION_OBSERVER_H_
+
+namespace mus {
+
+class Window;
+
+class WindowTreeConnectionObserver {
+ public:
+  virtual void OnWindowTreeFocusChanged(Window* gained_focus,
+                                        Window* lost_focus) {}
+
+ protected:
+  virtual ~WindowTreeConnectionObserver() {}
+};
+
+}  // namespace mus
+
+#endif  // COMPONENTS_MUS_PUBLIC_CPP_WINDOW_TREE_CONNECTION_OBSERVER_H_
diff --git a/components/mus/public/interfaces/BUILD.gn b/components/mus/public/interfaces/BUILD.gn
index cd27ea1..c20d0db 100644
--- a/components/mus/public/interfaces/BUILD.gn
+++ b/components/mus/public/interfaces/BUILD.gn
@@ -9,6 +9,7 @@
     "accelerator_registrar.mojom",
     "command_buffer.mojom",
     "compositor_frame.mojom",
+    "cursor.mojom",
     "gpu.mojom",
     "gpu_capabilities.mojom",
     "input_event_constants.mojom",
diff --git a/components/mus/public/interfaces/cursor.mojom b/components/mus/public/interfaces/cursor.mojom
new file mode 100644
index 0000000..c92aef2
--- /dev/null
+++ b/components/mus/public/interfaces/cursor.mojom
@@ -0,0 +1,57 @@
+// 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.
+
+module mus.mojom;
+
+// Standard Cursor numbers. These are the same as Chrome's ui::Cursor and
+// blink's WebCursorInfo.
+enum Cursor {
+  // NULL is kept for compatibility with chrome declarations. In chrome code, it
+  // is treated exactly like POINTER, the default pointer.
+  NULL = 0,
+  POINTER,
+  CROSS,
+  HAND,
+  IBEAM,
+  WAIT,
+  HELP,
+  EAST_RESIZE,
+  NORTH_RESIZE,
+  NORTH_EAST_RESIZE,
+  NORTH_WEST_RESIZE,
+  SOUTH_RESIZE,
+  SOUTH_EAST_RESIZE,
+  SOUTH_WEST_RESIZE,
+  WEST_RESIZE,
+  NORTH_SOUTH_RESIZE,
+  EAST_WEST_RESIZE,
+  NORTH_EAST_SOUTH_WEST_RESIZE,
+  NORTH_WEST_SOUTH_EAST_RESIZE,
+  COLUMN_RESIZE,
+  ROW_RESIZE,
+  MIDDLE_PANNING,
+  EAST_PANNING,
+  NORTH_PANNING,
+  NORTH_EAST_PANNING,
+  NORTH_WEST_PANNING,
+  SOUTH_PANNING,
+  SOUTH_EAST_PANNING,
+  SOUTH_WEST_PANNING,
+  WEST_PANNING,
+  MOVE,
+  VERTICAL_TEXT,
+  CELL,
+  CONTEXT_MENU,
+  ALIAS,
+  PROGRESS,
+  NO_DROP,
+  COPY,
+  NONE,
+  NOT_ALLOWED,
+  ZOOM_IN,
+  ZOOM_OUT,
+  GRAB,
+  GRABBING,
+  CUSTOM
+};
diff --git a/components/mus/public/interfaces/input_event_constants.mojom b/components/mus/public/interfaces/input_event_constants.mojom
index 587a17d..900fc24 100644
--- a/components/mus/public/interfaces/input_event_constants.mojom
+++ b/components/mus/public/interfaces/input_event_constants.mojom
@@ -18,19 +18,23 @@
 // This mirrors ui::EventFlags
 // TODO(morrita): Use shift operator once it is available.
 enum EventFlags {
-  NONE                =      0,
-  CAPS_LOCK_DOWN      =      1,
-  SHIFT_DOWN          =      2,
-  CONTROL_DOWN        =      4,
-  ALT_DOWN            =      8,
-  LEFT_MOUSE_BUTTON   =     16,
-  MIDDLE_MOUSE_BUTTON =     32,
-  RIGHT_MOUSE_BUTTON  =     64,
-  COMMAND_DOWN        =    128,
-  EXTENDED            =    256,
-  IS_SYNTHESIZED      =    512,
-  ALTGR_DOWN          =   1024,
-  MOD3_DOWN           =   2048
+  NONE                 =      0,
+  CAPS_LOCK_DOWN       =      1,
+  SHIFT_DOWN           =      2,
+  CONTROL_DOWN         =      4,
+  ALT_DOWN             =      8,
+  LEFT_MOUSE_BUTTON    =     16,
+  MIDDLE_MOUSE_BUTTON  =     32,
+  RIGHT_MOUSE_BUTTON   =     64,
+  COMMAND_DOWN         =    128,
+  EXTENDED             =    256,
+  IS_SYNTHESIZED       =    512,
+  ALTGR_DOWN           =   1024,
+  MOD3_DOWN            =   2048,
+  BACK_MOUSE_BUTTON    =   4096,
+  FORWARD_MOUSE_BUTTON =   8192,
+  NUM_LOCK_DOWN        =  16384,
+  SCROLL_LOCK_DOWN     =  32768,
 };
 
 enum MouseEventFlags {
diff --git a/components/mus/public/interfaces/input_event_matcher.mojom b/components/mus/public/interfaces/input_event_matcher.mojom
index 89c75c4..ec223e65 100644
--- a/components/mus/public/interfaces/input_event_matcher.mojom
+++ b/components/mus/public/interfaces/input_event_matcher.mojom
@@ -42,6 +42,9 @@
 struct EventMatcher {
   EventTypeMatcher? type_matcher;
   EventFlagsMatcher? flags_matcher;
+  // These flags will be stripped from incoming events' flags when comparing
+  // against |flags_matcher|.
+  EventFlagsMatcher? ignore_flags_matcher;
   KeyEventMatcher? key_matcher;
   PointerKindMatcher? pointer_kind_matcher;
   PointerLocationMatcher? pointer_location_matcher;
diff --git a/components/mus/public/interfaces/window_tree.mojom b/components/mus/public/interfaces/window_tree.mojom
index 9c64bb8..cc75ee4 100644
--- a/components/mus/public/interfaces/window_tree.mojom
+++ b/components/mus/public/interfaces/window_tree.mojom
@@ -5,6 +5,7 @@
 module mus.mojom;
 
 import "components/mus/public/interfaces/compositor_frame.mojom";
+import "components/mus/public/interfaces/cursor.mojom";
 import "components/mus/public/interfaces/input_events.mojom";
 import "components/mus/public/interfaces/mus_constants.mojom";
 import "components/mus/public/interfaces/surface_id.mojom";
@@ -100,8 +101,13 @@
   // Sets the specified bounds of the specified window.
   SetWindowBounds(uint32 change_id, uint32 window_id, mojo.Rect bounds);
 
-  // Sets the insets of the client area of the specified window.
-  SetClientArea(uint32 window_id, mojo.Insets insets);
+  // Sets the client area of the specified window. The client area is specified
+  // by way of insets. Everything outside of the insets, and not in
+  // |additional_client_areas| is considered non-client area.
+  // TODO(sky): convert additional_client_areas to a path.
+  SetClientArea(uint32 window_id,
+                mojo.Insets insets,
+                array<mojo.Rect>? additional_client_areas);
 
   // Sets the visibility of the specified window to |visible|. Connections are
   // allowed to change the visibility of any window they have created, as well
@@ -129,7 +135,7 @@
   //
   // This may result in a connection getting OnWindowDeleted(). See
   // RemoveWindowFromParent for details.
-  AddWindow(uint32 parent, uint32 child) => (bool success);
+  AddWindow(uint32 change_id, uint32 parent, uint32 child);
 
   // Removes a window from its current parent. This fails if the window is not
   // valid or the window already has no parent.
@@ -139,7 +145,7 @@
   // a child of 1. Connection B has a root 1. If 2 is removed from 1 then B gets
   // OnWindowDeleted(). This is done as window 2 is effectively no longer
   // visible to connection B.
-  RemoveWindowFromParent(uint32 window_id) => (bool success);
+  RemoveWindowFromParent(uint32 change_id, uint32 window_id);
 
   // Ties the lifetime of |child| to the lifetime of |parent|. This also
   // places |child| always on top of |parent|.
@@ -157,9 +163,10 @@
   // Reorders a window in its parent, relative to |relative_window_id| according
   // to |direction|. Only the connection that created the window's parent can
   // reorder its children.
-  ReorderWindow(uint32 window_id,
+  ReorderWindow(uint32 change_id,
+                uint32 window_id,
                 uint32 relative_window_id,
-                OrderDirection direction) => (bool success);
+                OrderDirection direction);
 
   // Returns the windows comprising the tree starting at |window_id|.
   // |window_id| is the first result in the return value, unless |window_id| is
@@ -201,9 +208,16 @@
         WindowTreeClient client,
         uint32 policy_bitmask) => (bool success, uint16 connection_id);
 
-  SetFocus(uint32 window_id);
+  SetFocus(uint32 change_id, uint32 window_id);
   SetCanFocus(uint32 window_id, bool can_focus);
 
+  // Sets the cursor when the pointer is inside |window_id| to a system standard
+  // cursor provided by the window manager.
+  SetPredefinedCursor(uint32 change_id, uint32 window_id, Cursor cursor_id);
+
+  // TODO(erg): Additional cursor methods. Image based cursors, visibility,
+  // and cursor locking.
+
   // Set text input state for the given window.
   SetWindowTextInputState(uint32 window_id, mojo.TextInputState state);
 
@@ -254,8 +268,8 @@
                         mojo.Rect new_bounds);
 
   OnClientAreaChanged(uint32 window_id,
-                      mojo.Insets old_client_area,
-                      mojo.Insets new_client_area);
+                      mojo.Insets new_client_area,
+                      array<mojo.Rect> new_additional_client_areas);
 
   OnTransientWindowAdded(uint32 window_id,
                          uint32 transient_window_id);
@@ -316,6 +330,8 @@
 
   OnWindowFocused(uint32 focused_window_id);
 
+  OnWindowPredefinedCursorChanged(uint32 window_id, Cursor cursor_id);
+
   // A change initiated from the client has completed. See description of
   // change ids for details.
   OnChangeCompleted(uint32 change_id, bool success);
diff --git a/components/mus/ws/BUILD.gn b/components/mus/ws/BUILD.gn
index 407b255..fd9918d 100644
--- a/components/mus/ws/BUILD.gn
+++ b/components/mus/ws/BUILD.gn
@@ -76,6 +76,7 @@
     "//mojo/converters/surfaces",
     "//mojo/public/cpp/bindings:callback",
     "//mojo/services/tracing/public/cpp",
+    "//ui/base",
     "//ui/events",
     "//ui/events/platform",
     "//ui/gfx",
diff --git a/components/mus/ws/access_policy.h b/components/mus/ws/access_policy.h
index 9b382fe..16eff90 100644
--- a/components/mus/ws/access_policy.h
+++ b/components/mus/ws/access_policy.h
@@ -50,6 +50,9 @@
   virtual bool CanSetWindowTextInputState(const ServerWindow* window) const = 0;
   virtual bool CanSetFocus(const ServerWindow* window) const = 0;
   virtual bool CanSetClientArea(const ServerWindow* window) const = 0;
+  // Used for all cursor properties; which cursor should be displayed,
+  // visibility, locking, etc.
+  virtual bool CanSetCursorProperties(const ServerWindow* window) const = 0;
 
   // Returns whether the connection should notify on a hierarchy change.
   // |new_parent| and |old_parent| are initially set to the new and old parents
diff --git a/components/mus/ws/connection_manager.cc b/components/mus/ws/connection_manager.cc
index 3c8bea5..b72b3f9 100644
--- a/components/mus/ws/connection_manager.cc
+++ b/components/mus/ws/connection_manager.cc
@@ -286,11 +286,11 @@
 
 void ConnectionManager::ProcessClientAreaChanged(
     const ServerWindow* window,
-    const gfx::Insets& old_client_area,
-    const gfx::Insets& new_client_area) {
+    const gfx::Insets& new_client_area,
+    const std::vector<gfx::Rect>& new_additional_client_areas) {
   for (auto& pair : connection_map_) {
     pair.second->service()->ProcessClientAreaChanged(
-        window, old_client_area, new_client_area,
+        window, new_client_area, new_additional_client_areas,
         IsOperationSource(pair.first));
   }
 }
@@ -338,6 +338,20 @@
   }
 }
 
+void ConnectionManager::ProcessWillChangeWindowPredefinedCursor(
+    ServerWindow* window,
+    int32_t cursor_id) {
+  for (auto& pair : connection_map_) {
+    pair.second->service()->ProcessCursorChanged(window, cursor_id,
+                                                 IsOperationSource(pair.first));
+  }
+
+  // Pass the cursor change to the native window.
+  WindowTreeHostImpl* host = GetWindowTreeHostByWindow(window);
+  if (host)
+    host->OnCursorUpdated(window);
+}
+
 void ConnectionManager::ProcessViewportMetricsChanged(
     const mojom::ViewportMetrics& old_metrics,
     const mojom::ViewportMetrics& new_metrics) {
@@ -434,12 +448,13 @@
 
 void ConnectionManager::OnWindowClientAreaChanged(
     ServerWindow* window,
-    const gfx::Insets& old_client_area,
-    const gfx::Insets& new_client_area) {
+    const gfx::Insets& new_client_area,
+    const std::vector<gfx::Rect>& new_additional_client_areas) {
   if (in_destructor_)
     return;
 
-  ProcessClientAreaChanged(window, old_client_area, new_client_area);
+  ProcessClientAreaChanged(window, new_client_area,
+                           new_additional_client_areas);
 }
 
 void ConnectionManager::OnWindowReordered(ServerWindow* window,
@@ -468,6 +483,14 @@
   }
 }
 
+void ConnectionManager::OnWindowPredefinedCursorChanged(ServerWindow* window,
+                                                        int32_t cursor_id) {
+  if (in_destructor_)
+    return;
+
+  ProcessWillChangeWindowPredefinedCursor(window, cursor_id);
+}
+
 void ConnectionManager::OnWindowSharedPropertyChanged(
     ServerWindow* window,
     const std::string& name,
diff --git a/components/mus/ws/connection_manager.h b/components/mus/ws/connection_manager.h
index c9cd68a..4ba4c93d 100644
--- a/components/mus/ws/connection_manager.h
+++ b/components/mus/ws/connection_manager.h
@@ -143,9 +143,10 @@
   void ProcessWindowBoundsChanged(const ServerWindow* window,
                                   const gfx::Rect& old_bounds,
                                   const gfx::Rect& new_bounds);
-  void ProcessClientAreaChanged(const ServerWindow* window,
-                                const gfx::Insets& old_client_area,
-                                const gfx::Insets& new_client_area);
+  void ProcessClientAreaChanged(
+      const ServerWindow* window,
+      const gfx::Insets& new_client_area,
+      const std::vector<gfx::Rect>& new_additional_client_areas);
   void ProcessViewportMetricsChanged(const mojom::ViewportMetrics& old_metrics,
                                      const mojom::ViewportMetrics& new_metrics);
   void ProcessWillChangeWindowHierarchy(const ServerWindow* window,
@@ -158,6 +159,8 @@
                             const ServerWindow* relative_window,
                             const mojom::OrderDirection direction);
   void ProcessWindowDeleted(const WindowId& window);
+  void ProcessWillChangeWindowPredefinedCursor(ServerWindow* window,
+                                               int32_t cursor_id);
 
  private:
   friend class Operation;
@@ -214,9 +217,10 @@
   void OnWindowBoundsChanged(ServerWindow* window,
                              const gfx::Rect& old_bounds,
                              const gfx::Rect& new_bounds) override;
-  void OnWindowClientAreaChanged(ServerWindow* window,
-                                 const gfx::Insets& old_client_area,
-                                 const gfx::Insets& new_client_area) override;
+  void OnWindowClientAreaChanged(
+      ServerWindow* window,
+      const gfx::Insets& new_client_area,
+      const std::vector<gfx::Rect>& new_additional_client_areas) override;
   void OnWindowReordered(ServerWindow* window,
                          ServerWindow* relative,
                          mojom::OrderDirection direction) override;
@@ -225,6 +229,8 @@
       ServerWindow* window,
       const std::string& name,
       const std::vector<uint8_t>* new_data) override;
+  void OnWindowPredefinedCursorChanged(ServerWindow* window,
+                                       int32_t cursor_id) override;
   void OnWindowTextInputStateChanged(ServerWindow* window,
                                      const ui::TextInputState& state) override;
   void OnTransientWindowAdded(ServerWindow* window,
diff --git a/components/mus/ws/default_access_policy.cc b/components/mus/ws/default_access_policy.cc
index 0a9cb241..2c7a89a 100644
--- a/components/mus/ws/default_access_policy.cc
+++ b/components/mus/ws/default_access_policy.cc
@@ -133,6 +133,12 @@
          delegate_->IsRootForAccessPolicy(window->id());
 }
 
+bool DefaultAccessPolicy::CanSetCursorProperties(
+    const ServerWindow* window) const {
+  return WasCreatedByThisConnection(window) ||
+         delegate_->IsRootForAccessPolicy(window->id());
+}
+
 bool DefaultAccessPolicy::ShouldNotifyOnHierarchyChange(
     const ServerWindow* window,
     const ServerWindow** new_parent,
diff --git a/components/mus/ws/default_access_policy.h b/components/mus/ws/default_access_policy.h
index f5b766d..f710f52 100644
--- a/components/mus/ws/default_access_policy.h
+++ b/components/mus/ws/default_access_policy.h
@@ -46,6 +46,7 @@
   bool CanSetWindowTextInputState(const ServerWindow* window) const override;
   bool CanSetFocus(const ServerWindow* window) const override;
   bool CanSetClientArea(const ServerWindow* window) const override;
+  bool CanSetCursorProperties(const ServerWindow* window) const override;
   bool ShouldNotifyOnHierarchyChange(
       const ServerWindow* window,
       const ServerWindow** new_parent,
diff --git a/components/mus/ws/display_manager.cc b/components/mus/ws/display_manager.cc
index afbe6e9..334dd024 100644
--- a/components/mus/ws/display_manager.cc
+++ b/components/mus/ws/display_manager.cc
@@ -29,6 +29,7 @@
 #include "mojo/converters/surfaces/surfaces_utils.h"
 #include "mojo/converters/transform/transform_type_converters.h"
 #include "third_party/skia/include/core/SkXfermode.h"
+#include "ui/base/cursor/cursor_loader.h"
 #include "ui/events/event.h"
 #include "ui/events/event_utils.h"
 #include "ui/gfx/display.h"
@@ -170,6 +171,9 @@
       delegate_(nullptr),
       draw_timer_(false, false),
       frame_pending_(false),
+#if !defined(OS_ANDROID)
+      cursor_loader_(ui::CursorLoader::Create()),
+#endif
       weak_factory_(this) {
   metrics_.size_in_pixels = mojo::Size::New();
   metrics_.size_in_pixels->width = 1024;
@@ -226,6 +230,19 @@
   platform_window_->SetTitle(title);
 }
 
+void DefaultDisplayManager::SetCursorById(int32_t cursor_id) {
+#if !defined(OS_ANDROID)
+  // TODO(erg): This still isn't sufficient, and will only use native cursors
+  // that chrome would use, not custom image cursors. For that, we should
+  // delegate to the window manager to load images from resource packs.
+  //
+  // We probably also need to deal with different DPIs.
+  ui::Cursor cursor(cursor_id);
+  cursor_loader_->SetPlatformCursor(&cursor);
+  platform_window_->SetCursor(cursor.platform());
+#endif
+}
+
 const mojom::ViewportMetrics& DefaultDisplayManager::GetViewportMetrics() {
   return metrics_;
 }
diff --git a/components/mus/ws/display_manager.h b/components/mus/ws/display_manager.h
index c8596b1..3705d96 100644
--- a/components/mus/ws/display_manager.h
+++ b/components/mus/ws/display_manager.h
@@ -32,6 +32,7 @@
 }  // namespace mojo
 
 namespace ui {
+class CursorLoader;
 class PlatformWindow;
 struct TextInputState;
 }  // namespace ui
@@ -68,6 +69,8 @@
 
   virtual void SetTitle(const base::string16& title) = 0;
 
+  virtual void SetCursorById(int32_t cursor) = 0;
+
   virtual const mojom::ViewportMetrics& GetViewportMetrics() = 0;
 
   virtual void UpdateTextInputState(const ui::TextInputState& state) = 0;
@@ -103,6 +106,7 @@
                      const gfx::Rect& bounds) override;
   void SetViewportSize(const gfx::Size& size) override;
   void SetTitle(const base::string16& title) override;
+  void SetCursorById(int32_t cursor) override;
   const mojom::ViewportMetrics& GetViewportMetrics() override;
   void UpdateTextInputState(const ui::TextInputState& state) override;
   void SetImeVisibility(bool visible) override;
@@ -149,6 +153,10 @@
   scoped_ptr<TopLevelDisplayClient> top_level_display_client_;
   scoped_ptr<ui::PlatformWindow> platform_window_;
 
+#if !defined(OS_ANDROID)
+  scoped_ptr<ui::CursorLoader> cursor_loader_;
+#endif
+
   base::WeakPtrFactory<DefaultDisplayManager> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(DefaultDisplayManager);
diff --git a/components/mus/ws/event_dispatcher.cc b/components/mus/ws/event_dispatcher.cc
index 384f9ba8..5265368 100644
--- a/components/mus/ws/event_dispatcher.cc
+++ b/components/mus/ws/event_dispatcher.cc
@@ -39,7 +39,15 @@
 
   gfx::Rect client_area(target->bounds().size());
   client_area.Inset(target->client_area());
-  return !client_area.Contains(location);
+  if (client_area.Contains(location))
+    return false;
+
+  for (const auto& rect : target->additional_client_areas()) {
+    if (rect.Contains(location))
+      return false;
+  }
+
+  return true;
 }
 
 gfx::Point EventLocationToPoint(const mojom::Event& event) {
@@ -55,6 +63,7 @@
       : fields_to_match_(NONE),
         event_type_(mojom::EVENT_TYPE_UNKNOWN),
         event_flags_(mojom::EVENT_FLAGS_NONE),
+        ignore_event_flags_(mojom::EVENT_FLAGS_NONE),
         keyboard_code_(mojom::KEYBOARD_CODE_UNKNOWN),
         pointer_kind_(mojom::POINTER_KIND_MOUSE) {
     if (matcher.type_matcher) {
@@ -64,6 +73,8 @@
     if (matcher.flags_matcher) {
       fields_to_match_ |= FLAGS;
       event_flags_ = matcher.flags_matcher->flags;
+      if (matcher.ignore_flags_matcher)
+        ignore_event_flags_ = matcher.ignore_flags_matcher->flags;
     }
     if (matcher.key_matcher) {
       fields_to_match_ |= KEYBOARD_CODE;
@@ -85,7 +96,9 @@
   bool MatchesEvent(const mojom::Event& event) const {
     if ((fields_to_match_ & TYPE) && event.action != event_type_)
       return false;
-    if ((fields_to_match_ & FLAGS) && event.flags != event_flags_)
+    mojom::EventFlags flags =
+        static_cast<mojom::EventFlags>(event.flags & ~ignore_event_flags_);
+    if ((fields_to_match_ & FLAGS) && flags != event_flags_)
       return false;
     if (fields_to_match_ & KEYBOARD_CODE) {
       if (!event.key_data)
@@ -113,6 +126,7 @@
     return fields_to_match_ == matcher.fields_to_match_ &&
            event_type_ == matcher.event_type_ &&
            event_flags_ == matcher.event_flags_ &&
+           ignore_event_flags_ == matcher.ignore_event_flags_ &&
            keyboard_code_ == matcher.keyboard_code_ &&
            pointer_kind_ == matcher.pointer_kind_ &&
            pointer_region_ == matcher.pointer_region_;
@@ -131,6 +145,7 @@
   uint32_t fields_to_match_;
   mojom::EventType event_type_;
   mojom::EventFlags event_flags_;
+  mojom::EventFlags ignore_event_flags_;
   mojom::KeyboardCode keyboard_code_;
   mojom::PointerKind pointer_kind_;
   gfx::RectF pointer_region_;
@@ -139,7 +154,10 @@
 ////////////////////////////////////////////////////////////////////////////////
 
 EventDispatcher::EventDispatcher(EventDispatcherDelegate* delegate)
-    : delegate_(delegate), root_(nullptr) {}
+    : delegate_(delegate),
+      root_(nullptr),
+      mouse_button_down_(false),
+      mouse_cursor_source_window_(nullptr) {}
 
 EventDispatcher::~EventDispatcher() {
   std::set<ServerWindow*> pointer_targets;
@@ -203,6 +221,10 @@
 }
 
 void EventDispatcher::ProcessPointerEvent(mojom::EventPtr event) {
+  bool is_mouse_event =
+      event->pointer_data &&
+      event->pointer_data->kind == mojom::PointerKind::POINTER_KIND_MOUSE;
+
   const int32_t pointer_id = event->pointer_data->pointer_id;
   if (event->action == mojom::EVENT_TYPE_WHEEL ||
       (event->action == mojom::EVENT_TYPE_POINTER_MOVE &&
@@ -215,6 +237,8 @@
       pointer_target.window =
           FindDeepestVisibleWindowForEvents(root_, surface_id_, &location);
     }
+    if (is_mouse_event && !mouse_button_down_)
+      mouse_cursor_source_window_ = pointer_target.window;
     DispatchToPointerTarget(pointer_target, event.Pass());
     return;
   }
@@ -230,6 +254,11 @@
     if (!IsObservingWindow(target))
       target->AddObserver(this);
 
+    if (is_mouse_event) {
+      mouse_button_down_ = true;
+      mouse_cursor_source_window_ = target;
+    }
+
     pointer_targets_[pointer_id].window = target;
     pointer_targets_[pointer_id].in_nonclient_area =
         IsLocationInNonclientArea(target, location);
@@ -246,6 +275,18 @@
       (event->pointer_data->kind != mojom::POINTER_KIND_MOUSE ||
        IsOnlyOneMouseButtonDown(event->flags));
 
+  if (should_reset_target && is_mouse_event) {
+    // When we release the mouse button, we want the cursor to be sourced from
+    // the window under the mouse pointer, even though we're sending the button
+    // up event to the window that had implicit capture. We have to set this
+    // before we perform dispatch because the Delegate is going to read this
+    // information from us.
+    mouse_button_down_ = false;
+    gfx::Point location(EventLocationToPoint(*event));
+    mouse_cursor_source_window_ =
+        FindDeepestVisibleWindowForEvents(root_, surface_id_, &location);
+  }
+
   DispatchToPointerTarget(pointer_targets_[pointer_id], event.Pass());
 
   if (should_reset_target) {
@@ -311,6 +352,9 @@
 
 void EventDispatcher::OnWindowDestroyed(ServerWindow* window) {
   CancelPointerEventsToTarget(window);
+
+  if (mouse_cursor_source_window_ == window)
+    mouse_cursor_source_window_ = nullptr;
 }
 
 }  // namespace ws
diff --git a/components/mus/ws/event_dispatcher.h b/components/mus/ws/event_dispatcher.h
index a6ffd62..505713c 100644
--- a/components/mus/ws/event_dispatcher.h
+++ b/components/mus/ws/event_dispatcher.h
@@ -33,6 +33,11 @@
 
   void set_surface_id(cc::SurfaceId surface_id) { surface_id_ = surface_id; }
 
+  // Retrieves the ServerWindow of the last mouse move.
+  ServerWindow* mouse_cursor_source_window() const {
+    return mouse_cursor_source_window_;
+  }
+
   // Adds an accelerator with the given id and event-matcher. If an accelerator
   // already exists with the same id or the same matcher, then the accelerator
   // is not added. Returns whether adding the accelerator was successful or not.
@@ -95,6 +100,9 @@
   EventDispatcherDelegate* delegate_;
   ServerWindow* root_;
 
+  bool mouse_button_down_;
+  ServerWindow* mouse_cursor_source_window_;
+
   cc::SurfaceId surface_id_;
 
   using Entry = std::pair<uint32_t, EventMatcher>;
diff --git a/components/mus/ws/event_dispatcher_unittest.cc b/components/mus/ws/event_dispatcher_unittest.cc
index d837dbc..010a017b 100644
--- a/components/mus/ws/event_dispatcher_unittest.cc
+++ b/components/mus/ws/event_dispatcher_unittest.cc
@@ -219,6 +219,14 @@
   EXPECT_EQ(accelerator_1,
             event_dispatcher_delegate.GetAndClearLastAccelerator());
 
+  // EF_NUM_LOCK_DOWN should be ignored since CreateKeyMatcher defaults to
+  // ignoring.
+  key = ui::KeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_W,
+                     ui::EF_CONTROL_DOWN | ui::EF_NUM_LOCK_DOWN);
+  dispatcher.OnEvent(mojom::Event::From(key));
+  EXPECT_EQ(accelerator_1,
+            event_dispatcher_delegate.GetAndClearLastAccelerator());
+
   key = ui::KeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_W, ui::EF_NONE);
   dispatcher.OnEvent(mojom::Event::From(key));
   EXPECT_EQ(0u, event_dispatcher_delegate.GetAndClearLastAccelerator());
@@ -344,7 +352,7 @@
   root.SetBounds(gfx::Rect(0, 0, 100, 100));
   child.SetBounds(gfx::Rect(10, 10, 20, 20));
 
-  child.SetClientArea(gfx::Insets(5, 5, 5, 5));
+  child.SetClientArea(gfx::Insets(5, 5, 5, 5), std::vector<gfx::Rect>());
 
   TestEventDispatcherDelegate event_dispatcher_delegate(&root);
   EventDispatcher dispatcher(&event_dispatcher_delegate);
@@ -393,6 +401,40 @@
   EXPECT_FALSE(event_dispatcher_delegate.GetAndClearLastInNonclientArea());
 }
 
+TEST(EventDispatcherTest, AdditionalClientArea) {
+  TestServerWindowDelegate window_delegate;
+  ServerWindow root(&window_delegate, WindowId(1, 2));
+  window_delegate.set_root_window(&root);
+  root.SetVisible(true);
+
+  ServerWindow child(&window_delegate, WindowId(1, 3));
+  root.Add(&child);
+  child.SetVisible(true);
+  EnableHitTest(&child);
+
+  root.SetBounds(gfx::Rect(0, 0, 100, 100));
+  child.SetBounds(gfx::Rect(10, 10, 20, 20));
+
+  std::vector<gfx::Rect> additional_client_areas;
+  additional_client_areas.push_back(gfx::Rect(18, 0, 2, 2));
+  child.SetClientArea(gfx::Insets(5, 5, 5, 5), additional_client_areas);
+
+  TestEventDispatcherDelegate event_dispatcher_delegate(&root);
+  EventDispatcher dispatcher(&event_dispatcher_delegate);
+  dispatcher.set_root(&root);
+
+  // Press in the additional client area, it should go to the child.
+  const ui::MouseEvent press_event(
+      ui::ET_MOUSE_PRESSED, gfx::Point(28, 11), gfx::Point(28, 11),
+      base::TimeDelta(), ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
+  dispatcher.OnEvent(
+      mojom::Event::From(static_cast<const ui::Event&>(press_event)));
+
+  // Events should target child and be in the client area.
+  ASSERT_EQ(&child, event_dispatcher_delegate.last_target());
+  EXPECT_FALSE(event_dispatcher_delegate.GetAndClearLastInNonclientArea());
+}
+
 TEST(EventDispatcherTest, DontFocusOnSecondDown) {
   TestServerWindowDelegate window_delegate;
   ServerWindow root(&window_delegate, WindowId(1, 2));
diff --git a/components/mus/ws/operation.h b/components/mus/ws/operation.h
index 27441a6..76b4111 100644
--- a/components/mus/ws/operation.h
+++ b/components/mus/ws/operation.h
@@ -27,6 +27,7 @@
   REORDER_WINDOW,
   SET_FOCUS,
   SET_WINDOW_BOUNDS,
+  SET_WINDOW_PREDEFINED_CURSOR,
   SET_WINDOW_PROPERTY,
   SET_WINDOW_VISIBILITY,
 };
diff --git a/components/mus/ws/server_window.cc b/components/mus/ws/server_window.cc
index 29b8ec1..c0bcffaf 100644
--- a/components/mus/ws/server_window.cc
+++ b/components/mus/ws/server_window.cc
@@ -29,6 +29,7 @@
       stacking_target_(nullptr),
       transient_parent_(nullptr),
       visible_(false),
+      cursor_id_(mojom::CURSOR_NULL),
       opacity_(1),
       can_focus_(true),
       properties_(properties),
@@ -159,14 +160,19 @@
                     OnWindowBoundsChanged(this, old_bounds, bounds));
 }
 
-void ServerWindow::SetClientArea(const gfx::Insets& insets) {
-  if (client_area_ == insets)
+void ServerWindow::SetClientArea(
+    const gfx::Insets& insets,
+    const std::vector<gfx::Rect>& additional_client_areas) {
+  if (client_area_ == insets &&
+      additional_client_areas == additional_client_areas_) {
     return;
+  }
 
-  const gfx::Insets old_client_area = client_area_;
+  additional_client_areas_ = additional_client_areas;
   client_area_ = insets;
-  FOR_EACH_OBSERVER(ServerWindowObserver, observers_,
-                    OnWindowClientAreaChanged(this, old_client_area, insets));
+  FOR_EACH_OBSERVER(
+      ServerWindowObserver, observers_,
+      OnWindowClientAreaChanged(this, insets, additional_client_areas));
 }
 
 const ServerWindow* ServerWindow::GetRoot() const {
@@ -261,6 +267,15 @@
   delegate_->OnScheduleWindowPaint(this);
 }
 
+void ServerWindow::SetPredefinedCursor(mus::mojom::Cursor value) {
+  if (value == cursor_id_)
+    return;
+  cursor_id_ = value;
+  FOR_EACH_OBSERVER(
+      ServerWindowObserver, observers_,
+      OnWindowPredefinedCursorChanged(this, static_cast<int32_t>(value)));
+}
+
 void ServerWindow::SetTransform(const gfx::Transform& transform) {
   if (transform_ == transform)
     return;
diff --git a/components/mus/ws/server_window.h b/components/mus/ws/server_window.h
index 7cadc08..f20d785 100644
--- a/components/mus/ws/server_window.h
+++ b/components/mus/ws/server_window.h
@@ -71,8 +71,14 @@
   // area to fill the whole bounds.
   void SetBounds(const gfx::Rect& bounds);
 
+  const std::vector<gfx::Rect>& additional_client_areas() const {
+    return additional_client_areas_;
+  }
   const gfx::Insets& client_area() const { return client_area_; }
-  void SetClientArea(const gfx::Insets& insets);
+  void SetClientArea(const gfx::Insets& insets,
+                     const std::vector<gfx::Rect>& additional_client_areas);
+
+  int32_t cursor() const { return cursor_id_; }
 
   const ServerWindow* parent() const { return parent_; }
   ServerWindow* parent() { return parent_; }
@@ -111,6 +117,8 @@
   float opacity() const { return opacity_; }
   void SetOpacity(float value);
 
+  void SetPredefinedCursor(mus::mojom::Cursor cursor_id);
+
   const gfx::Transform& transform() const { return transform_; }
   void SetTransform(const gfx::Transform& transform);
 
@@ -190,7 +198,9 @@
   bool visible_;
   gfx::Rect bounds_;
   gfx::Insets client_area_;
+  std::vector<gfx::Rect> additional_client_areas_;
   scoped_ptr<ServerWindowSurfaceManager> surface_manager_;
+  mojom::Cursor cursor_id_;
   float opacity_;
   bool can_focus_;
   gfx::Transform transform_;
diff --git a/components/mus/ws/server_window_observer.h b/components/mus/ws/server_window_observer.h
index 61d5d16..04273b2e 100644
--- a/components/mus/ws/server_window_observer.h
+++ b/components/mus/ws/server_window_observer.h
@@ -5,6 +5,8 @@
 #ifndef COMPONENTS_MUS_WS_SERVER_WINDOW_OBSERVER_H_
 #define COMPONENTS_MUS_WS_SERVER_WINDOW_OBSERVER_H_
 
+#include <vector>
+
 #include "components/mus/public/interfaces/mus_constants.mojom.h"
 
 namespace gfx {
@@ -45,9 +47,10 @@
                                      const gfx::Rect& old_bounds,
                                      const gfx::Rect& new_bounds) {}
 
-  virtual void OnWindowClientAreaChanged(ServerWindow* window,
-                                         const gfx::Insets& old_client_area,
-                                         const gfx::Insets& new_client_area) {}
+  virtual void OnWindowClientAreaChanged(
+      ServerWindow* window,
+      const gfx::Insets& new_client_area,
+      const std::vector<gfx::Rect>& new_additional_client_areas) {}
 
   virtual void OnWindowReordered(ServerWindow* window,
                                  ServerWindow* relative,
@@ -56,6 +59,9 @@
   virtual void OnWillChangeWindowVisibility(ServerWindow* window) {}
   virtual void OnWindowVisibilityChanged(ServerWindow* window) {}
 
+  virtual void OnWindowPredefinedCursorChanged(ServerWindow* window,
+                                               int32_t cursor_id) {}
+
   virtual void OnWindowTextInputStateChanged(ServerWindow* window,
                                              const ui::TextInputState& state) {}
 
diff --git a/components/mus/ws/test_change_tracker.cc b/components/mus/ws/test_change_tracker.cc
index a128c017..7b5750d 100644
--- a/components/mus/ws/test_change_tracker.cc
+++ b/components/mus/ws/test_change_tracker.cc
@@ -111,6 +111,11 @@
     case CHANGE_TYPE_FOCUSED:
       return base::StringPrintf("Focused id=%s",
                                 WindowIdToString(change.window_id).c_str());
+
+    case CHANGE_TYPE_CURSOR_CHANGED:
+      return base::StringPrintf("CursorChanged id=%s cursor_id=%d",
+                                WindowIdToString(change.window_id).c_str(),
+                                change.cursor_id);
   }
   return std::string();
 }
@@ -327,6 +332,16 @@
   AddChange(change);
 }
 
+void TestChangeTracker::OnWindowPredefinedCursorChanged(
+    Id window_id,
+    mojom::Cursor cursor_id) {
+  Change change;
+  change.type = CHANGE_TYPE_CURSOR_CHANGED;
+  change.window_id = window_id;
+  change.cursor_id = cursor_id;
+  AddChange(change);
+}
+
 void TestChangeTracker::DelegateEmbed(const String& url) {
   Change change;
   change.type = CHANGE_TYPE_DELEGATE_EMBED;
diff --git a/components/mus/ws/test_change_tracker.h b/components/mus/ws/test_change_tracker.h
index aa7a5a6..df9b6d6 100644
--- a/components/mus/ws/test_change_tracker.h
+++ b/components/mus/ws/test_change_tracker.h
@@ -36,6 +36,7 @@
   CHANGE_TYPE_PROPERTY_CHANGED,
   CHANGE_TYPE_DELEGATE_EMBED,
   CHANGE_TYPE_FOCUSED,
+  CHANGE_TYPE_CURSOR_CHANGED
 };
 
 // TODO(sky): consider nuking and converting directly to WindowData.
@@ -76,6 +77,7 @@
   bool bool_value;
   std::string property_key;
   std::string property_value;
+  int32_t cursor_id;
 };
 
 // Converts Changes to string descriptions.
@@ -146,6 +148,7 @@
                                      mojo::String name,
                                      mojo::Array<uint8_t> data);
   void OnWindowFocused(Id window_id);
+  void OnWindowPredefinedCursorChanged(Id window_id, mojom::Cursor cursor_id);
   void DelegateEmbed(const mojo::String& url);
 
  private:
diff --git a/components/mus/ws/window_manager_access_policy.cc b/components/mus/ws/window_manager_access_policy.cc
index 69c17f1e..a3fa1700 100644
--- a/components/mus/ws/window_manager_access_policy.cc
+++ b/components/mus/ws/window_manager_access_policy.cc
@@ -113,6 +113,12 @@
          delegate_->IsRootForAccessPolicy(window->id());
 }
 
+bool WindowManagerAccessPolicy::CanSetCursorProperties(
+    const ServerWindow* window) const {
+  return window->id().connection_id == connection_id_ ||
+         delegate_->IsRootForAccessPolicy(window->id());
+}
+
 bool WindowManagerAccessPolicy::ShouldNotifyOnHierarchyChange(
     const ServerWindow* window,
     const ServerWindow** new_parent,
diff --git a/components/mus/ws/window_manager_access_policy.h b/components/mus/ws/window_manager_access_policy.h
index ba1c6b47..8781cf5 100644
--- a/components/mus/ws/window_manager_access_policy.h
+++ b/components/mus/ws/window_manager_access_policy.h
@@ -45,6 +45,7 @@
   bool CanSetWindowTextInputState(const ServerWindow* window) const override;
   bool CanSetFocus(const ServerWindow* window) const override;
   bool CanSetClientArea(const ServerWindow* window) const override;
+  bool CanSetCursorProperties(const ServerWindow* window) const override;
   bool ShouldNotifyOnHierarchyChange(
       const ServerWindow* window,
       const ServerWindow** new_parent,
diff --git a/components/mus/ws/window_manager_client_apptest.cc b/components/mus/ws/window_manager_client_apptest.cc
index b2ef3f5..db0be04 100644
--- a/components/mus/ws/window_manager_client_apptest.cc
+++ b/components/mus/ws/window_manager_client_apptest.cc
@@ -9,6 +9,7 @@
 #include "components/mus/public/cpp/tests/window_server_test_base.h"
 #include "components/mus/public/cpp/window_observer.h"
 #include "components/mus/public/cpp/window_tree_connection.h"
+#include "components/mus/public/cpp/window_tree_connection_observer.h"
 #include "components/mus/public/cpp/window_tree_delegate.h"
 #include "mojo/application/public/cpp/application_connection.h"
 #include "mojo/application/public/cpp/application_impl.h"
@@ -66,8 +67,10 @@
 
  private:
   // Overridden from WindowObserver:
-  void OnWindowClientAreaChanged(Window* window,
-                                 const gfx::Insets& old_client_area) override {
+  void OnWindowClientAreaChanged(
+      Window* window,
+      const gfx::Insets& old_client_area,
+      const std::vector<gfx::Rect>& old_additional_client_areas) override {
     DCHECK_EQ(window, window_);
     EXPECT_TRUE(WindowServerTestBase::QuitRunLoop());
   }
@@ -608,11 +611,14 @@
   explicit FocusChangeObserver(Window* window)
       : window_(window),
         last_gained_focus_(nullptr),
-        last_lost_focus_(nullptr) {
+        last_lost_focus_(nullptr),
+        quit_on_change_(true) {
     window_->AddObserver(this);
   }
   ~FocusChangeObserver() override { window_->RemoveObserver(this); }
 
+  void set_quit_on_change(bool value) { quit_on_change_ = value; }
+
   Window* last_gained_focus() { return last_gained_focus_; }
 
   Window* last_lost_focus() { return last_lost_focus_; }
@@ -624,16 +630,39 @@
     EXPECT_FALSE(lost_focus && lost_focus->HasFocus());
     last_gained_focus_ = gained_focus;
     last_lost_focus_ = lost_focus;
-    EXPECT_TRUE(WindowServerTestBase::QuitRunLoop());
+    if (quit_on_change_)
+      EXPECT_TRUE(WindowServerTestBase::QuitRunLoop());
   }
 
   Window* window_;
   Window* last_gained_focus_;
   Window* last_lost_focus_;
+  bool quit_on_change_;
 
   MOJO_DISALLOW_COPY_AND_ASSIGN(FocusChangeObserver);
 };
 
+class NullFocusChangeObserver : public WindowTreeConnectionObserver {
+ public:
+  explicit NullFocusChangeObserver(WindowTreeConnection* connection)
+      : connection_(connection) {
+    connection_->AddObserver(this);
+  }
+  ~NullFocusChangeObserver() override { connection_->RemoveObserver(this); }
+
+ private:
+  // Overridden from WindowTreeConnectionObserver.
+  void OnWindowTreeFocusChanged(Window* gained_focus,
+                                Window* lost_focus) override {
+    if (!gained_focus)
+      EXPECT_TRUE(WindowServerTestBase::QuitRunLoop());
+  }
+
+  WindowTreeConnection* connection_;
+
+  MOJO_DISALLOW_COPY_AND_ASSIGN(NullFocusChangeObserver);
+};
+
 bool WaitForWindowToHaveFocus(Window* window) {
   if (window->HasFocus())
     return true;
@@ -641,6 +670,13 @@
   return WindowServerTestBase::DoRunLoopWithTimeout();
 }
 
+bool WaitForNoWindowToHaveFocus(WindowTreeConnection* connection) {
+  if (!connection->GetFocusedWindow())
+    return true;
+  NullFocusChangeObserver observer(connection);
+  return WindowServerTestBase::DoRunLoopWithTimeout();
+}
+
 }  // namespace
 
 TEST_F(WindowServerTest, Focus) {
@@ -654,31 +690,39 @@
   window11->SetVisible(true);
   embedded->GetRoot()->AddChild(window11);
 
-  // TODO(alhaad): Figure out why switching focus between windows from different
-  // connections is causing the tests to crash and add tests for that.
   {
+    // Focus the embed root in |embedded|.
     Window* embedded_root = embedded->GetRoot();
     FocusChangeObserver observer(embedded_root);
+    observer.set_quit_on_change(false);
     embedded_root->SetFocus();
-    ASSERT_TRUE(DoRunLoopWithTimeout());
+    ASSERT_TRUE(embedded_root->HasFocus());
     ASSERT_NE(nullptr, observer.last_gained_focus());
     EXPECT_EQ(embedded_root->id(), observer.last_gained_focus()->id());
+
+    // |embedded_root| is the same as |window1|, make sure |window1| got
+    // focus too.
+    ASSERT_TRUE(WaitForWindowToHaveFocus(window1));
   }
+
+  // Focus a child of embedded->GetRoot().
   {
     FocusChangeObserver observer(window11);
+    observer.set_quit_on_change(false);
     window11->SetFocus();
-    ASSERT_TRUE(DoRunLoopWithTimeout());
+    ASSERT_TRUE(window11->HasFocus());
     ASSERT_NE(nullptr, observer.last_gained_focus());
     ASSERT_NE(nullptr, observer.last_lost_focus());
     EXPECT_EQ(window11->id(), observer.last_gained_focus()->id());
     EXPECT_EQ(embedded->GetRoot()->id(), observer.last_lost_focus()->id());
   }
+
   {
     // Add an observer on the Window that loses focus, and make sure the
     // observer sees the right values.
     FocusChangeObserver observer(window11);
+    observer.set_quit_on_change(false);
     embedded->GetRoot()->SetFocus();
-    ASSERT_TRUE(DoRunLoopWithTimeout());
     ASSERT_NE(nullptr, observer.last_gained_focus());
     ASSERT_NE(nullptr, observer.last_lost_focus());
     EXPECT_EQ(window11->id(), observer.last_lost_focus()->id());
@@ -737,6 +781,7 @@
       WaitForWindowToHaveFocus(window_manager()->GetWindowById(child21->id())));
   EXPECT_EQ(child21->id(), window_manager()->GetFocusedWindow()->id());
   EXPECT_EQ(child21->id(), embedded2->GetFocusedWindow()->id());
+  EXPECT_TRUE(WaitForNoWindowToHaveFocus(embedded1));
   EXPECT_EQ(nullptr, embedded1->GetFocusedWindow());
   EXPECT_GT(ValidIndexOf(parent->children(), child2),
             ValidIndexOf(parent->children(), child1));
diff --git a/components/mus/ws/window_tree_apptest.cc b/components/mus/ws/window_tree_apptest.cc
index 3895571..cbf3c57d 100644
--- a/components/mus/ws/window_tree_apptest.cc
+++ b/components/mus/ws/window_tree_apptest.cc
@@ -44,13 +44,6 @@
 // Callback function from WindowTree functions.
 // ----------------------------------
 
-void BoolResultCallback(base::RunLoop* run_loop,
-                        bool* result_cache,
-                        bool result) {
-  *result_cache = result;
-  run_loop->Quit();
-}
-
 void WindowTreeResultCallback(base::RunLoop* run_loop,
                               std::vector<TestWindow>* windows,
                               Array<WindowDataPtr> results) {
@@ -95,36 +88,6 @@
   return result;
 }
 
-bool AddWindow(WindowTree* ws, Id parent, Id child) {
-  bool result = false;
-  base::RunLoop run_loop;
-  ws->AddWindow(parent, child,
-                base::Bind(&BoolResultCallback, &run_loop, &result));
-  run_loop.Run();
-  return result;
-}
-
-bool RemoveWindowFromParent(WindowTree* ws, Id window_id) {
-  bool result = false;
-  base::RunLoop run_loop;
-  ws->RemoveWindowFromParent(
-      window_id, base::Bind(&BoolResultCallback, &run_loop, &result));
-  run_loop.Run();
-  return result;
-}
-
-bool ReorderWindow(WindowTree* ws,
-                   Id window_id,
-                   Id relative_window_id,
-                   mojom::OrderDirection direction) {
-  bool result = false;
-  base::RunLoop run_loop;
-  ws->ReorderWindow(window_id, relative_window_id, direction,
-                    base::Bind(&BoolResultCallback, &run_loop, &result));
-  run_loop.Run();
-  return result;
-}
-
 void GetWindowTree(WindowTree* ws,
                    Id window_id,
                    std::vector<TestWindow>* windows) {
@@ -214,6 +177,26 @@
     return WaitForChangeCompleted(change_id);
   }
 
+  bool AddWindow(Id parent, Id child) {
+    const uint32_t change_id = GetAndAdvanceChangeId();
+    tree()->AddWindow(change_id, parent, child);
+    return WaitForChangeCompleted(change_id);
+  }
+
+  bool RemoveWindowFromParent(Id window_id) {
+    const uint32_t change_id = GetAndAdvanceChangeId();
+    tree()->RemoveWindowFromParent(change_id, window_id);
+    return WaitForChangeCompleted(change_id);
+  }
+
+  bool ReorderWindow(Id window_id,
+                     Id relative_window_id,
+                     mojom::OrderDirection direction) {
+    const uint32_t change_id = GetAndAdvanceChangeId();
+    tree()->ReorderWindow(change_id, window_id, relative_window_id, direction);
+    return WaitForChangeCompleted(change_id);
+  }
+
   // Waits for all messages to be received by |ws|. This is done by attempting
   // to create a bogus window. When we get the response we know all messages
   // have been processed.
@@ -248,6 +231,12 @@
     return WaitForChangeCompleted(change_id);
   }
 
+  bool SetPredefinedCursor(Id window_id, mojom::Cursor cursor) {
+    const uint32_t change_id = GetAndAdvanceChangeId();
+    tree()->SetPredefinedCursor(change_id, window_id, cursor);
+    return WaitForChangeCompleted(change_id);
+  }
+
   bool SetWindowVisibility(Id window_id, bool visible) {
     const uint32_t change_id = GetAndAdvanceChangeId();
     tree()->SetWindowVisibility(change_id, window_id, visible);
@@ -300,9 +289,10 @@
     tracker()->OnWindowBoundsChanged(window_id, old_bounds.Pass(),
                                      new_bounds.Pass());
   }
-  void OnClientAreaChanged(uint32_t window_id,
-                           mojo::InsetsPtr old_client_area,
-                           mojo::InsetsPtr new_client_area) override {}
+  void OnClientAreaChanged(
+      uint32_t window_id,
+      mojo::InsetsPtr new_client_area,
+      mojo::Array<mojo::RectPtr> new_additional_client_areas) override {}
   void OnTransientWindowAdded(uint32_t window_id,
                               uint32_t transient_window_id) override {
     tracker()->OnTransientWindowAdded(window_id, transient_window_id);
@@ -350,6 +340,10 @@
   }
   // TODO(sky): add testing coverage.
   void OnWindowFocused(uint32_t focused_window_id) override {}
+  void OnWindowPredefinedCursorChanged(uint32 window_id,
+                                       mojom::Cursor cursor_id) override {
+    tracker_.OnWindowPredefinedCursorChanged(window_id, cursor_id);
+  }
   void OnChangeCompleted(uint32_t change_id, bool success) override {
     if (waiting_change_id_ == change_id && change_completed_run_loop_) {
       on_change_completed_result_ = success;
@@ -592,11 +586,11 @@
   // Two windows 1 and 2. 2 is parented to 1.
   Id window_1_1 = ws_client1()->NewWindow(1);
   ASSERT_TRUE(window_1_1);
-  ASSERT_TRUE(AddWindow(ws1(), root_window_id(), window_1_1));
+  ASSERT_TRUE(ws_client1()->AddWindow(root_window_id(), window_1_1));
 
   Id window_1_2 = ws_client1()->NewWindow(2);
   ASSERT_TRUE(window_1_2);
-  ASSERT_TRUE(AddWindow(ws1(), window_1_1, window_1_2));
+  ASSERT_TRUE(ws_client1()->AddWindow(window_1_1, window_1_2));
 
   ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(false));
   ASSERT_EQ(1u, changes2()->size());
@@ -630,7 +624,7 @@
   Id window_2_4 = ws_client2()->NewWindow(4);
   ASSERT_TRUE(window_2_3);
   ASSERT_TRUE(window_2_4);
-  ASSERT_TRUE(AddWindow(ws2(), window_2_3, window_2_4));
+  ASSERT_TRUE(ws_client2()->AddWindow(window_2_3, window_2_4));
 
   // Connection 3 rooted at 2.
   ASSERT_NO_FATAL_FAILURE(EstablishThirdConnection(ws2(), window_2_3));
@@ -665,13 +659,13 @@
   Id window_1_1 = BuildWindowId(connection_id_1(), 1);
   Id window_2_2 = ws_client2()->NewWindow(2);
   ASSERT_TRUE(window_2_2);
-  ASSERT_TRUE(AddWindow(ws2(), window_1_1, window_2_2));
+  ASSERT_TRUE(ws_client2()->AddWindow(window_1_1, window_2_2));
 
   ASSERT_NO_FATAL_FAILURE(EstablishThirdConnection(ws2(), window_2_2));
 
   Id window_3_3 = ws_client3()->NewWindow(3);
   ASSERT_TRUE(window_3_3);
-  ASSERT_TRUE(AddWindow(ws3(), window_2_2, window_3_3));
+  ASSERT_TRUE(ws_client3()->AddWindow(window_2_2, window_3_3));
 
   // Even though 3 is a child of 2 connection 2 can't see 3 as it's from a
   // different connection.
@@ -710,22 +704,22 @@
   Id window_1_1 = BuildWindowId(connection_id_1(), 1);
   Id window_2_2 = ws_client2()->NewWindow(2);
   ASSERT_TRUE(window_2_2);
-  ASSERT_TRUE(AddWindow(ws2(), window_1_1, window_2_2));
+  ASSERT_TRUE(ws_client2()->AddWindow(window_1_1, window_2_2));
 
   ASSERT_NO_FATAL_FAILURE(EstablishThirdConnection(ws2(), window_2_2));
 
   Id window_2_3 = ws_client2()->NewWindow(3);
   ASSERT_TRUE(window_2_3);
   // Connection 2 shouldn't be able to add anything to the window anymore.
-  ASSERT_FALSE(AddWindow(ws2(), window_2_2, window_2_3));
+  ASSERT_FALSE(ws_client2()->AddWindow(window_2_2, window_2_3));
 
   // Create window 3 in connection 3 and add it to window 3.
   Id window_3_3 = ws_client3()->NewWindow(3);
   ASSERT_TRUE(window_3_3);
-  ASSERT_TRUE(AddWindow(ws3(), window_2_2, window_3_3));
+  ASSERT_TRUE(ws_client3()->AddWindow(window_2_2, window_3_3));
 
   // Connection 2 shouldn't be able to remove window 3.
-  ASSERT_FALSE(RemoveWindowFromParent(ws2(), window_3_3));
+  ASSERT_FALSE(ws_client2()->RemoveWindowFromParent(window_3_3));
 }
 
 // Verifies client gets a valid id.
@@ -754,10 +748,10 @@
   ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true));
 
   // Make 3 a child of 2.
-  ASSERT_TRUE(AddWindow(ws1(), window_1_2, window_1_3));
+  ASSERT_TRUE(ws_client1()->AddWindow(window_1_2, window_1_3));
 
   // Try again, this should fail.
-  EXPECT_FALSE(AddWindow(ws1(), window_1_2, window_1_3));
+  EXPECT_FALSE(ws_client1()->AddWindow(window_1_2, window_1_3));
 }
 
 // Verifies AddWindow fails when window is already in position.
@@ -770,10 +764,10 @@
   ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true));
 
   // Make 3 a child of 2.
-  ASSERT_TRUE(AddWindow(ws1(), window_1_2, window_1_3));
+  ASSERT_TRUE(ws_client1()->AddWindow(window_1_2, window_1_3));
 
   // Try to make 2 a child of 3, this should fail since 2 is an ancestor of 3.
-  EXPECT_FALSE(AddWindow(ws1(), window_1_3, window_1_2));
+  EXPECT_FALSE(ws_client1()->AddWindow(window_1_3, window_1_2));
 }
 
 // Verifies adding to root sends right notifications.
@@ -788,10 +782,10 @@
   changes2()->clear();
 
   // Make 3 a child of 21.
-  ASSERT_TRUE(AddWindow(ws1(), window_1_21, window_1_3));
+  ASSERT_TRUE(ws_client1()->AddWindow(window_1_21, window_1_3));
 
   // Make 21 a child of 1.
-  ASSERT_TRUE(AddWindow(ws1(), window_1_1, window_1_21));
+  ASSERT_TRUE(ws_client1()->AddWindow(window_1_1, window_1_21));
 
   // Connection 2 should not be told anything (because the window is from a
   // different connection). Create a window to ensure we got a response from
@@ -809,7 +803,7 @@
   Id window_1_11 = ws_client1()->NewWindow(11);
   ASSERT_TRUE(window_1_11);
   ASSERT_TRUE(ws_client1()->SetWindowVisibility(window_1_11, true));
-  ASSERT_TRUE(AddWindow(ws1(), window_1_2, window_1_11));
+  ASSERT_TRUE(ws_client1()->AddWindow(window_1_2, window_1_11));
 
   Id window_1_1 = BuildWindowId(connection_id_1(), 1);
   ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true));
@@ -821,7 +815,7 @@
   // 1,1->1,2->1,11
   {
     // Client 2 should not get anything (1,2 is from another connection).
-    ASSERT_TRUE(AddWindow(ws1(), window_1_1, window_1_2));
+    ASSERT_TRUE(ws_client1()->AddWindow(window_1_1, window_1_2));
     ASSERT_TRUE(ws_client2()->WaitForAllMessages());
     EXPECT_TRUE(changes2()->empty());
   }
@@ -830,7 +824,7 @@
   {
     // Client 2 is now connected to the root, so it should have gotten a drawn
     // notification.
-    ASSERT_TRUE(AddWindow(ws1(), root_window_id(), window_1_1));
+    ASSERT_TRUE(ws_client1()->AddWindow(root_window_id(), window_1_1));
     ws_client2_->WaitForChangeCount(1u);
     EXPECT_EQ(
         "DrawnStateChanged window=" + IdToString(window_1_1) + " drawn=true",
@@ -842,7 +836,7 @@
     // Client 2 is no longer connected to the root, should get drawn state
     // changed.
     changes2()->clear();
-    ASSERT_TRUE(RemoveWindowFromParent(ws1(), window_1_1));
+    ASSERT_TRUE(ws_client1()->RemoveWindowFromParent(window_1_1));
     ws_client2_->WaitForChangeCount(1);
     EXPECT_EQ(
         "DrawnStateChanged window=" + IdToString(window_1_1) + " drawn=false",
@@ -855,7 +849,7 @@
   ASSERT_TRUE(ws_client1()->SetWindowVisibility(window_1_111, true));
   {
     changes2()->clear();
-    ASSERT_TRUE(AddWindow(ws1(), window_1_11, window_1_111));
+    ASSERT_TRUE(ws_client1()->AddWindow(window_1_11, window_1_111));
     ASSERT_TRUE(ws_client2()->WaitForAllMessages());
     EXPECT_TRUE(changes2()->empty());
   }
@@ -863,7 +857,7 @@
   // 0,1->1,1->1,2->1,11->1,111
   {
     changes2()->clear();
-    ASSERT_TRUE(AddWindow(ws1(), root_window_id(), window_1_1));
+    ASSERT_TRUE(ws_client1()->AddWindow(root_window_id(), window_1_1));
     ws_client2_->WaitForChangeCount(1);
     EXPECT_EQ(
         "DrawnStateChanged window=" + IdToString(window_1_1) + " drawn=true",
@@ -885,14 +879,14 @@
   ASSERT_TRUE(window_2_21);
 
   // Set up the hierarchy.
-  ASSERT_TRUE(AddWindow(ws1(), root_window_id(), window_1_1));
-  ASSERT_TRUE(AddWindow(ws2(), window_1_1, window_2_11));
-  ASSERT_TRUE(AddWindow(ws2(), window_2_2, window_2_21));
+  ASSERT_TRUE(ws_client1()->AddWindow(root_window_id(), window_1_1));
+  ASSERT_TRUE(ws_client2()->AddWindow(window_1_1, window_2_11));
+  ASSERT_TRUE(ws_client2()->AddWindow(window_2_2, window_2_21));
 
   // Remove 11, should result in a hierarchy change for the root.
   {
     changes1()->clear();
-    ASSERT_TRUE(RemoveWindowFromParent(ws2(), window_2_11));
+    ASSERT_TRUE(ws_client2()->RemoveWindowFromParent(window_2_11));
 
     ws_client1_->WaitForChangeCount(1);
     EXPECT_EQ("HierarchyChanged window=" + IdToString(window_2_11) +
@@ -903,7 +897,7 @@
   // Add 2 to 1.
   {
     changes1()->clear();
-    ASSERT_TRUE(AddWindow(ws2(), window_1_1, window_2_2));
+    ASSERT_TRUE(ws_client2()->AddWindow(window_1_1, window_2_2));
     ws_client1_->WaitForChangeCount(1);
     EXPECT_EQ("HierarchyChanged window=" + IdToString(window_2_2) +
                   " new_parent=" + IdToString(window_1_1) + " old_parent=null",
@@ -934,17 +928,17 @@
   ASSERT_TRUE(window_2_7);
   ASSERT_TRUE(window_2_8);
 
-  ASSERT_TRUE(AddWindow(ws2(), window_2_1, window_2_2));
-  ASSERT_TRUE(AddWindow(ws2(), window_2_2, window_2_6));
-  ASSERT_TRUE(AddWindow(ws2(), window_2_1, window_2_3));
-  ASSERT_TRUE(AddWindow(ws1(), root_window_id(), window_1_4));
-  ASSERT_TRUE(AddWindow(ws1(), root_window_id(), window_1_5));
-  ASSERT_TRUE(AddWindow(ws1(), root_window_id(), window_2_1));
+  ASSERT_TRUE(ws_client2()->AddWindow(window_2_1, window_2_2));
+  ASSERT_TRUE(ws_client2()->AddWindow(window_2_2, window_2_6));
+  ASSERT_TRUE(ws_client2()->AddWindow(window_2_1, window_2_3));
+  ASSERT_TRUE(ws_client1()->AddWindow(root_window_id(), window_1_4));
+  ASSERT_TRUE(ws_client1()->AddWindow(root_window_id(), window_1_5));
+  ASSERT_TRUE(ws_client1()->AddWindow(root_window_id(), window_2_1));
 
   {
     changes1()->clear();
-    ASSERT_TRUE(ReorderWindow(ws2(), window_2_2, window_2_3,
-                              mojom::ORDER_DIRECTION_ABOVE));
+    ASSERT_TRUE(ws_client2()->ReorderWindow(window_2_2, window_2_3,
+                                            mojom::ORDER_DIRECTION_ABOVE));
 
     ws_client1_->WaitForChangeCount(1);
     EXPECT_EQ("Reordered window=" + IdToString(window_2_2) + " relative=" +
@@ -954,8 +948,8 @@
 
   {
     changes1()->clear();
-    ASSERT_TRUE(ReorderWindow(ws2(), window_2_2, window_2_3,
-                              mojom::ORDER_DIRECTION_BELOW));
+    ASSERT_TRUE(ws_client2()->ReorderWindow(window_2_2, window_2_3,
+                                            mojom::ORDER_DIRECTION_BELOW));
 
     ws_client1_->WaitForChangeCount(1);
     EXPECT_EQ("Reordered window=" + IdToString(window_2_2) + " relative=" +
@@ -964,25 +958,25 @@
   }
 
   // view2 is already below view3.
-  EXPECT_FALSE(ReorderWindow(ws2(), window_2_2, window_2_3,
-                             mojom::ORDER_DIRECTION_BELOW));
+  EXPECT_FALSE(ws_client2()->ReorderWindow(window_2_2, window_2_3,
+                                           mojom::ORDER_DIRECTION_BELOW));
 
   // view4 & 5 are unknown to connection2_.
-  EXPECT_FALSE(ReorderWindow(ws2(), window_1_4, window_1_5,
-                             mojom::ORDER_DIRECTION_ABOVE));
+  EXPECT_FALSE(ws_client2()->ReorderWindow(window_1_4, window_1_5,
+                                           mojom::ORDER_DIRECTION_ABOVE));
 
   // view6 & view3 have different parents.
-  EXPECT_FALSE(ReorderWindow(ws1(), window_2_3, window_2_6,
-                             mojom::ORDER_DIRECTION_ABOVE));
+  EXPECT_FALSE(ws_client1()->ReorderWindow(window_2_3, window_2_6,
+                                           mojom::ORDER_DIRECTION_ABOVE));
 
   // Non-existent window-ids
-  EXPECT_FALSE(ReorderWindow(ws1(), BuildWindowId(connection_id_1(), 27),
-                             BuildWindowId(connection_id_1(), 28),
-                             mojom::ORDER_DIRECTION_ABOVE));
+  EXPECT_FALSE(ws_client1()->ReorderWindow(BuildWindowId(connection_id_1(), 27),
+                                           BuildWindowId(connection_id_1(), 28),
+                                           mojom::ORDER_DIRECTION_ABOVE));
 
   // view7 & view8 are un-parented.
-  EXPECT_FALSE(ReorderWindow(ws1(), window_2_7, window_2_8,
-                             mojom::ORDER_DIRECTION_ABOVE));
+  EXPECT_FALSE(ws_client1()->ReorderWindow(window_2_7, window_2_8,
+                                           mojom::ORDER_DIRECTION_ABOVE));
 }
 
 // Verifies DeleteWindow works.
@@ -995,7 +989,7 @@
   // Make 2 a child of 1.
   {
     changes1()->clear();
-    ASSERT_TRUE(AddWindow(ws2(), window_1_1, window_2_2));
+    ASSERT_TRUE(ws_client2()->AddWindow(window_1_1, window_2_2));
     ws_client1_->WaitForChangeCount(1);
     EXPECT_EQ("HierarchyChanged window=" + IdToString(window_2_2) +
                   " new_parent=" + IdToString(window_1_1) + " old_parent=null",
@@ -1032,7 +1026,7 @@
   // Add 2 to 1.
   {
     changes1()->clear();
-    ASSERT_TRUE(AddWindow(ws2(), window_1_1, window_2_2));
+    ASSERT_TRUE(ws_client2()->AddWindow(window_1_1, window_2_2));
     ws_client1_->WaitForChangeCount(1);
     EXPECT_EQ("HierarchyChanged window=" + IdToString(window_2_2) +
                   " new_parent=" + IdToString(window_1_1) + " old_parent=null",
@@ -1056,7 +1050,7 @@
   ASSERT_TRUE(window_2_2);
   {
     changes1()->clear();
-    ASSERT_TRUE(AddWindow(ws2(), window_1_1, window_2_2));
+    ASSERT_TRUE(ws_client2()->AddWindow(window_1_1, window_2_2));
 
     ws_client1_->WaitForChangeCount(1);
     EXPECT_EQ("HierarchyChanged window=" + IdToString(window_2_2) +
@@ -1075,16 +1069,16 @@
   // Create 11 in first connection and make it a child of 1.
   Id window_1_11 = ws_client1()->NewWindow(11);
   ASSERT_TRUE(window_1_11);
-  ASSERT_TRUE(AddWindow(ws1(), root_window_id(), window_1_1));
-  ASSERT_TRUE(AddWindow(ws1(), window_1_1, window_1_11));
+  ASSERT_TRUE(ws_client1()->AddWindow(root_window_id(), window_1_1));
+  ASSERT_TRUE(ws_client1()->AddWindow(window_1_1, window_1_11));
 
   // Create two windows in second connection, 2 and 3, both children of 1.
   Id window_2_2 = ws_client2()->NewWindow(2);
   Id window_2_3 = ws_client2()->NewWindow(3);
   ASSERT_TRUE(window_2_2);
   ASSERT_TRUE(window_2_3);
-  ASSERT_TRUE(AddWindow(ws2(), window_1_1, window_2_2));
-  ASSERT_TRUE(AddWindow(ws2(), window_1_1, window_2_3));
+  ASSERT_TRUE(ws_client2()->AddWindow(window_1_1, window_2_2));
+  ASSERT_TRUE(ws_client2()->AddWindow(window_1_1, window_2_3));
 
   // Verifies GetWindowTree() on the root. The root connection sees all.
   {
@@ -1129,7 +1123,7 @@
 TEST_F(WindowTreeAppTest, SetWindowBounds) {
   Id window_1_1 = ws_client1()->NewWindow(1);
   ASSERT_TRUE(window_1_1);
-  ASSERT_TRUE(AddWindow(ws1(), root_window_id(), window_1_1));
+  ASSERT_TRUE(ws_client1()->AddWindow(root_window_id(), window_1_1));
 
   ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(false));
 
@@ -1163,11 +1157,11 @@
 
   // Try to move 2 to be a child of 1 from connection 2. This should fail as 2
   // should not be able to access 1.
-  ASSERT_FALSE(AddWindow(ws2(), window_1_1, window_1_2));
+  ASSERT_FALSE(ws_client2()->AddWindow(window_1_1, window_1_2));
 
   // Try to reparent 1 to the root. A connection is not allowed to reparent its
   // roots.
-  ASSERT_FALSE(AddWindow(ws2(), root_window_id(), window_1_1));
+  ASSERT_FALSE(ws_client2()->AddWindow(root_window_id(), window_1_1));
 }
 
 // Verify RemoveWindowFromParent fails for windows that are descendants of the
@@ -1179,15 +1173,15 @@
   ASSERT_TRUE(window_1_1);
   ASSERT_TRUE(window_1_2);
 
-  ASSERT_TRUE(AddWindow(ws1(), root_window_id(), window_1_1));
-  ASSERT_TRUE(AddWindow(ws1(), root_window_id(), window_1_2));
+  ASSERT_TRUE(ws_client1()->AddWindow(root_window_id(), window_1_1));
+  ASSERT_TRUE(ws_client1()->AddWindow(root_window_id(), window_1_2));
 
   // Establish the second connection and give it the root 1.
   ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(false));
 
   // Connection 2 should not be able to remove window 2 or 1 from its parent.
-  ASSERT_FALSE(RemoveWindowFromParent(ws2(), window_1_2));
-  ASSERT_FALSE(RemoveWindowFromParent(ws2(), window_1_1));
+  ASSERT_FALSE(ws_client2()->RemoveWindowFromParent(window_1_2));
+  ASSERT_FALSE(ws_client2()->RemoveWindowFromParent(window_1_1));
 
   // Create windows 10 and 11 in 2.
   Id window_2_10 = ws_client2()->NewWindow(10);
@@ -1196,9 +1190,9 @@
   ASSERT_TRUE(window_2_11);
 
   // Parent 11 to 10.
-  ASSERT_TRUE(AddWindow(ws2(), window_2_10, window_2_11));
+  ASSERT_TRUE(ws_client2()->AddWindow(window_2_10, window_2_11));
   // Remove 11 from 10.
-  ASSERT_TRUE(RemoveWindowFromParent(ws2(), window_2_11));
+  ASSERT_TRUE(ws_client2()->RemoveWindowFromParent(window_2_11));
 
   // Verify nothing was actually removed.
   {
@@ -1222,8 +1216,8 @@
   ASSERT_TRUE(window_1_1);
   ASSERT_TRUE(window_1_2);
 
-  ASSERT_TRUE(AddWindow(ws1(), root_window_id(), window_1_1));
-  ASSERT_TRUE(AddWindow(ws1(), root_window_id(), window_1_2));
+  ASSERT_TRUE(ws_client1()->AddWindow(root_window_id(), window_1_1));
+  ASSERT_TRUE(ws_client1()->AddWindow(root_window_id(), window_1_2));
 
   ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(false));
 
@@ -1281,7 +1275,7 @@
   // Create a window in the third connection and parent it to the root.
   Id window_3_1 = ws_client3()->NewWindow(1);
   ASSERT_TRUE(window_3_1);
-  ASSERT_TRUE(AddWindow(ws3(), window_1_1, window_3_1));
+  ASSERT_TRUE(ws_client3()->AddWindow(window_1_1, window_3_1));
 
   // Connection 1 should have been told about the add (it owns the window).
   {
@@ -1344,7 +1338,7 @@
   ASSERT_TRUE(window_1_1);
   ASSERT_TRUE(window_1_2);
 
-  ASSERT_TRUE(AddWindow(ws1(), root_window_id(), window_1_1));
+  ASSERT_TRUE(ws_client1()->AddWindow(root_window_id(), window_1_1));
   {
     std::vector<TestWindow> windows;
     GetWindowTree(ws1(), root_window_id(), &windows);
@@ -1384,7 +1378,7 @@
   }
 
   // Attach 2 to 1.
-  ASSERT_TRUE(AddWindow(ws1(), window_1_1, window_1_2));
+  ASSERT_TRUE(ws_client1()->AddWindow(window_1_1, window_1_2));
   {
     std::vector<TestWindow> windows;
     GetWindowTree(ws1(), window_1_1, &windows);
@@ -1412,6 +1406,21 @@
   }
 }
 
+// Test that we hear the cursor change in other connections.
+TEST_F(WindowTreeAppTest, SetCursor) {
+  // Get a second connection to listen in.
+  ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true));
+  Id window_1_1 = BuildWindowId(connection_id_1(), 1);
+  changes2()->clear();
+
+  ASSERT_TRUE(ws_client1()->SetPredefinedCursor(window_1_1,
+                                                mojom::Cursor::CURSOR_IBEAM));
+  ws_client2_->WaitForChangeCount(1u);
+
+  EXPECT_EQ("CursorChanged id=" + IdToString(window_1_1) + " cursor_id=4",
+            SingleChangeToDescription(*changes2()));
+}
+
 // Assertions for SetWindowVisibility sending notifications.
 TEST_F(WindowTreeAppTest, SetWindowVisibilityNotifications) {
   // Create 1,1 and 1,2. 1,2 is made a child of 1,1 and 1,1 a child of the root.
@@ -1421,8 +1430,8 @@
   Id window_1_2 = ws_client1()->NewWindow(2);
   ASSERT_TRUE(window_1_2);
   ASSERT_TRUE(ws_client1()->SetWindowVisibility(window_1_2, true));
-  ASSERT_TRUE(AddWindow(ws1(), root_window_id(), window_1_1));
-  ASSERT_TRUE(AddWindow(ws1(), window_1_1, window_1_2));
+  ASSERT_TRUE(ws_client1()->AddWindow(root_window_id(), window_1_1));
+  ASSERT_TRUE(ws_client1()->AddWindow(window_1_1, window_1_2));
 
   // Establish the second connection at 1,2.
   ASSERT_NO_FATAL_FAILURE(EstablishSecondConnectionWithRoot(window_1_2));
@@ -1431,7 +1440,7 @@
   Id window_2_3 = ws_client2()->NewWindow(3);
   ASSERT_TRUE(window_2_3);
   ASSERT_TRUE(ws_client2()->SetWindowVisibility(window_2_3, true));
-  ASSERT_TRUE(AddWindow(ws2(), window_1_2, window_2_3));
+  ASSERT_TRUE(ws_client2()->AddWindow(window_1_2, window_2_3));
   ASSERT_TRUE(ws_client1()->WaitForAllMessages());
 
   changes2()->clear();
@@ -1486,7 +1495,7 @@
 
   changes2()->clear();
   // Remove 1,1 from the root, connection 2 should see drawn state changed.
-  ASSERT_TRUE(RemoveWindowFromParent(ws1(), window_1_1));
+  ASSERT_TRUE(ws_client1()->RemoveWindowFromParent(window_1_1));
   {
     ws_client2_->WaitForChangeCount(1);
     EXPECT_EQ(
@@ -1496,7 +1505,7 @@
 
   changes2()->clear();
   // Add 1,1 back to the root, connection 2 should see drawn state changed.
-  ASSERT_TRUE(AddWindow(ws1(), root_window_id(), window_1_1));
+  ASSERT_TRUE(ws_client1()->AddWindow(root_window_id(), window_1_1));
   {
     ws_client2_->WaitForChangeCount(1);
     EXPECT_EQ(
@@ -1512,7 +1521,7 @@
   ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(false));
   changes2()->clear();
 
-  ASSERT_TRUE(AddWindow(ws1(), root_window_id(), window_1_1));
+  ASSERT_TRUE(ws_client1()->AddWindow(root_window_id(), window_1_1));
   {
     std::vector<TestWindow> windows;
     GetWindowTree(ws1(), root_window_id(), &windows);
@@ -1559,7 +1568,7 @@
   Id window_1_1 = BuildWindowId(connection_id_1(), 1);
   Id window_2_2 = ws_client2()->NewWindow(2);
   ASSERT_TRUE(window_2_2);
-  ASSERT_TRUE(AddWindow(ws2(), window_1_1, window_2_2));
+  ASSERT_TRUE(ws_client2()->AddWindow(window_1_1, window_2_2));
   changes2()->clear();
   ASSERT_NO_FATAL_FAILURE(EstablishThirdConnection(ws2(), window_2_2));
 
@@ -1585,13 +1594,13 @@
   // Create connection 2 and 3.
   ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true));
   Id window_1_1 = BuildWindowId(connection_id_1(), 1);
-  ASSERT_TRUE(AddWindow(ws1(), root_window_id(), window_1_1));
+  ASSERT_TRUE(ws_client1()->AddWindow(root_window_id(), window_1_1));
   Id window_2_2 = ws_client2()->NewWindow(2);
   Id window_2_3 = ws_client2()->NewWindow(3);
   ASSERT_TRUE(window_2_2);
   ASSERT_TRUE(window_2_3);
-  ASSERT_TRUE(AddWindow(ws2(), window_1_1, window_2_2));
-  ASSERT_TRUE(AddWindow(ws2(), window_2_2, window_2_3));
+  ASSERT_TRUE(ws_client2()->AddWindow(window_1_1, window_2_2));
+  ASSERT_TRUE(ws_client2()->AddWindow(window_2_2, window_2_3));
   changes2()->clear();
   ASSERT_NO_FATAL_FAILURE(EstablishThirdConnection(ws2(), window_2_3));
   changes3()->clear();
@@ -1639,12 +1648,12 @@
   Id window_1_1 = BuildWindowId(connection_id_1(), 1);
   Id window_2_2 = ws_client2()->NewWindow(2);
   ASSERT_TRUE(window_2_2);
-  ASSERT_TRUE(AddWindow(ws2(), window_1_1, window_2_2));
+  ASSERT_TRUE(ws_client2()->AddWindow(window_1_1, window_2_2));
   ASSERT_NO_FATAL_FAILURE(EstablishThirdConnection(ws2(), window_2_2));
 
   Id window_3_3 = ws_client3()->NewWindow(3);
   ASSERT_TRUE(window_3_3);
-  ASSERT_TRUE(AddWindow(ws3(), window_2_2, window_3_3));
+  ASSERT_TRUE(ws_client3()->AddWindow(window_2_2, window_3_3));
 
   // 2 should not be able to embed in window_3_3 as window_3_3 was not created
   // by
@@ -1660,7 +1669,7 @@
   Id window_1_1 = BuildWindowId(connection_id_1(), 1);
   Id window_2_2 = ws_client2()->NewWindow(2);
   ASSERT_TRUE(window_2_2);
-  ASSERT_TRUE(AddWindow(ws2(), window_1_1, window_2_2));
+  ASSERT_TRUE(ws_client2()->AddWindow(window_1_1, window_2_2));
 
   changes2()->clear();
 
@@ -1692,7 +1701,7 @@
   Id window_1_2 = ws_client1()->NewWindow(2);
   ASSERT_TRUE(window_1_2);
   ASSERT_TRUE(
-      AddWindow(ws1(), BuildWindowId(connection_id_1(), 1), window_1_2));
+      ws_client1()->AddWindow(BuildWindowId(connection_id_1(), 1), window_1_2));
   ASSERT_TRUE(ws_client3_.get() == nullptr);
   ws_client3_ = EstablishConnectionViaEmbedWithPolicyBitmask(
       ws1(), window_1_2, mojom::WindowTree::ACCESS_POLICY_EMBED_ROOT, nullptr);
@@ -1718,10 +1727,10 @@
   // root -> window_1_1 -> window_2_1
   // root -> window_1_1 -> window_2_2
   // root -> window_1_1 -> window_2_3
-  ASSERT_TRUE(AddWindow(ws1(), root_window_id(), window_1_1));
-  ASSERT_TRUE(AddWindow(ws2(), window_1_1, window_2_1));
-  ASSERT_TRUE(AddWindow(ws2(), window_1_1, window_2_2));
-  ASSERT_TRUE(AddWindow(ws2(), window_1_1, window_2_3));
+  ASSERT_TRUE(ws_client1()->AddWindow(root_window_id(), window_1_1));
+  ASSERT_TRUE(ws_client2()->AddWindow(window_1_1, window_2_1));
+  ASSERT_TRUE(ws_client2()->AddWindow(window_1_1, window_2_2));
+  ASSERT_TRUE(ws_client2()->AddWindow(window_1_1, window_2_3));
 
   // window_2_2 and window_2_3 now track the lifetime of window_2_1.
   changes1()->clear();
diff --git a/components/mus/ws/window_tree_host_impl.cc b/components/mus/ws/window_tree_host_impl.cc
index 8214b692..413f52a 100644
--- a/components/mus/ws/window_tree_host_impl.cc
+++ b/components/mus/ws/window_tree_host_impl.cc
@@ -7,6 +7,7 @@
 #include "base/debug/debugger.h"
 #include "base/strings/utf_string_conversions.h"
 #include "components/mus/common/types.h"
+#include "components/mus/public/interfaces/input_event_constants.mojom.h"
 #include "components/mus/ws/connection_manager.h"
 #include "components/mus/ws/display_manager.h"
 #include "components/mus/ws/focus_controller.h"
@@ -43,7 +44,8 @@
       display_manager_(
           DisplayManager::Create(app_impl, gpu_state, surfaces_state)),
       window_manager_(window_manager.Pass()),
-      tree_awaiting_input_ack_(nullptr) {
+      tree_awaiting_input_ack_(nullptr),
+      last_cursor_(0) {
   display_manager_->Init(this);
   if (client_) {
     client_.set_connection_error_handler(base::Bind(
@@ -131,6 +133,11 @@
   display_manager_->SetImeVisibility(visible);
 }
 
+void WindowTreeHostImpl::OnCursorUpdated(ServerWindow* window) {
+  if (window == event_dispatcher_.mouse_cursor_source_window())
+    UpdateNativeCursor(window->cursor());
+}
+
 void WindowTreeHostImpl::SetSize(mojo::SizePtr size) {
   display_manager_->SetViewportSize(size.To<gfx::Size>());
 }
@@ -217,6 +224,13 @@
   event_dispatcher_.OnEvent(next_event.Pass());
 }
 
+void WindowTreeHostImpl::UpdateNativeCursor(int32_t cursor_id) {
+  if (cursor_id != last_cursor_) {
+    display_manager_->SetCursorById(cursor_id);
+    last_cursor_ = cursor_id;
+  }
+}
+
 ServerWindow* WindowTreeHostImpl::GetRootWindow() {
   return root_.get();
 }
@@ -366,6 +380,14 @@
                                                     bool in_nonclient_area,
                                                     mojom::EventPtr event) {
   DCHECK(!event_ack_timer_.IsRunning());
+
+  if (event->pointer_data &&
+      event->pointer_data->kind == mojom::PointerKind::POINTER_KIND_MOUSE) {
+    DCHECK(event_dispatcher_.mouse_cursor_source_window());
+    UpdateNativeCursor(
+        event_dispatcher_.mouse_cursor_source_window()->cursor());
+  }
+
   // If the event is in the non-client area the event goes to the owner of
   // the window. Otherwise if the window is an embed root, forward to the
   // embedded window.
diff --git a/components/mus/ws/window_tree_host_impl.h b/components/mus/ws/window_tree_host_impl.h
index 3ed61fe..1d50dc0e 100644
--- a/components/mus/ws/window_tree_host_impl.h
+++ b/components/mus/ws/window_tree_host_impl.h
@@ -93,6 +93,10 @@
                             const ui::TextInputState& state);
   void SetImeVisibility(ServerWindow* window, bool visible);
 
+  // Called when a client updates a cursor. This will update the cursor on the
+  // native display if the cursor is currently under |window|.
+  void OnCursorUpdated(ServerWindow* window);
+
   // WindowTreeHost:
   void SetSize(mojo::SizePtr size) override;
   void SetTitle(const mojo::String& title) override;
@@ -118,6 +122,8 @@
   void OnEventAckTimeout();
   void DispatchNextEventFromQueue();
 
+  void UpdateNativeCursor(int32_t cursor_id);
+
   // DisplayManagerDelegate:
   ServerWindow* GetRootWindow() override;
   void OnEvent(mojom::EventPtr event) override;
@@ -159,6 +165,9 @@
   mojom::WindowManagerPtr window_manager_;
   mojom::WindowTree* tree_awaiting_input_ack_;
 
+  // The last cursor set. Used to track whether we need to change the cursor.
+  int32_t last_cursor_;
+
   std::set<WindowId> activation_parents_;
 
   // Set of windows with surfaces that need to be destroyed once the frame
diff --git a/components/mus/ws/window_tree_impl.cc b/components/mus/ws/window_tree_impl.cc
index 38c9305..b58cc5b 100644
--- a/components/mus/ws/window_tree_impl.cc
+++ b/components/mus/ws/window_tree_impl.cc
@@ -221,14 +221,14 @@
 
 void WindowTreeImpl::ProcessClientAreaChanged(
     const ServerWindow* window,
-    const gfx::Insets& old_client_area,
     const gfx::Insets& new_client_area,
+    const std::vector<gfx::Rect>& new_additional_client_areas,
     bool originated_change) {
   if (originated_change || !IsWindowKnown(window))
     return;
-  client()->OnClientAreaChanged(WindowIdToTransportId(window->id()),
-                                mojo::Insets::From(old_client_area),
-                                mojo::Insets::From(new_client_area));
+  client()->OnClientAreaChanged(
+      WindowIdToTransportId(window->id()), mojo::Insets::From(new_client_area),
+      mojo::Array<mojo::RectPtr>::From(new_additional_client_areas));
 }
 
 void WindowTreeImpl::ProcessViewportMetricsChanged(
@@ -364,6 +364,15 @@
   NotifyDrawnStateChanged(window, window_target_drawn_state);
 }
 
+void WindowTreeImpl::ProcessCursorChanged(const ServerWindow* window,
+                                          int32_t cursor_id,
+                                          bool originated_change) {
+  if (originated_change)
+    return;
+  client()->OnWindowPredefinedCursorChanged(WindowIdToTransportId(window->id()),
+                                            mojom::Cursor(cursor_id));
+}
+
 void WindowTreeImpl::ProcessFocusChanged(
     const ServerWindow* old_focused_window,
     const ServerWindow* new_focused_window) {
@@ -648,16 +657,13 @@
   client_->OnChangeCompleted(change_id, success);
 }
 
-void WindowTreeImpl::AddWindow(Id parent_id,
-                               Id child_id,
-                               const Callback<void(bool)>& callback) {
-  callback.Run(AddWindow(WindowIdFromTransportId(parent_id),
-                         WindowIdFromTransportId(child_id)));
+void WindowTreeImpl::AddWindow(uint32_t change_id, Id parent_id, Id child_id) {
+  client_->OnChangeCompleted(change_id,
+                             AddWindow(WindowIdFromTransportId(parent_id),
+                                       WindowIdFromTransportId(child_id)));
 }
 
-void WindowTreeImpl::RemoveWindowFromParent(
-    Id window_id,
-    const Callback<void(bool)>& callback) {
+void WindowTreeImpl::RemoveWindowFromParent(uint32_t change_id, Id window_id) {
   bool success = false;
   ServerWindow* window = GetWindow(WindowIdFromTransportId(window_id));
   if (window && window->parent() &&
@@ -667,7 +673,7 @@
                  OperationType::REMOVE_WINDOW_FROM_PARENT);
     window->parent()->Remove(window);
   }
-  callback.Run(success);
+  client_->OnChangeCompleted(change_id, success);
 }
 
 void WindowTreeImpl::AddTransientWindow(uint32_t change_id,
@@ -694,10 +700,10 @@
   client_->OnChangeCompleted(change_id, success);
 }
 
-void WindowTreeImpl::ReorderWindow(Id window_id,
+void WindowTreeImpl::ReorderWindow(uint32_t change_id,
+                                   Id window_id,
                                    Id relative_window_id,
-                                   mojom::OrderDirection direction,
-                                   const Callback<void(bool)>& callback) {
+                                   mojom::OrderDirection direction) {
   bool success = false;
   ServerWindow* window = GetWindow(WindowIdFromTransportId(window_id));
   ServerWindow* relative_window =
@@ -709,7 +715,7 @@
     connection_manager_->ProcessWindowReorder(window, relative_window,
                                               direction);
   }
-  callback.Run(success);
+  client_->OnChangeCompleted(change_id, success);
 }
 
 void WindowTreeImpl::GetWindowTree(
@@ -787,7 +793,7 @@
   window->CreateSurface(type, surface.Pass(), client.Pass());
 }
 
-void WindowTreeImpl::SetWindowTextInputState(uint32_t window_id,
+void WindowTreeImpl::SetWindowTextInputState(Id window_id,
                                              mojo::TextInputStatePtr state) {
   ServerWindow* window = GetWindow(WindowIdFromTransportId(window_id));
   bool success = window && access_policy_->CanSetWindowTextInputState(window);
@@ -820,14 +826,18 @@
   GetHost()->OnEventAck(this);
 }
 
-void WindowTreeImpl::SetClientArea(Id transport_window_id,
-                                   mojo::InsetsPtr insets) {
+void WindowTreeImpl::SetClientArea(
+    Id transport_window_id,
+    mojo::InsetsPtr insets,
+    mojo::Array<mojo::RectPtr> transport_additional_client_areas) {
   ServerWindow* window =
       GetWindow(WindowIdFromTransportId(transport_window_id));
   if (!window || !access_policy_->CanSetClientArea(window))
     return;
 
-  window->SetClientArea(insets.To<gfx::Insets>());
+  std::vector<gfx::Rect> additional_client_areas =
+      transport_additional_client_areas.To<std::vector<gfx::Rect>>();
+  window->SetClientArea(insets.To<gfx::Insets>(), additional_client_areas);
 }
 
 void WindowTreeImpl::Embed(Id transport_window_id,
@@ -840,24 +850,41 @@
   callback.Run(result, connection_id);
 }
 
-void WindowTreeImpl::SetFocus(uint32_t window_id) {
+void WindowTreeImpl::SetFocus(uint32_t change_id, Id window_id) {
   ServerWindow* window = GetWindow(WindowIdFromTransportId(window_id));
   // TODO(beng): consider shifting non-policy drawn check logic to VTH's
   //             FocusController.
-  if (window && window->IsDrawn() && access_policy_->CanSetFocus(window)) {
+  WindowTreeHostImpl* host = GetHost();
+  const bool success = window && window->IsDrawn() &&
+                       access_policy_->CanSetFocus(window) && host;
+  if (success) {
     Operation op(this, connection_manager_, OperationType::SET_FOCUS);
-    WindowTreeHostImpl* host = GetHost();
-    if (host)
-      host->SetFocusedWindow(window);
+    host->SetFocusedWindow(window);
   }
+  client_->OnChangeCompleted(change_id, success);
 }
 
-void WindowTreeImpl::SetCanFocus(uint32_t window_id, bool can_focus) {
+void WindowTreeImpl::SetCanFocus(Id window_id, bool can_focus) {
   ServerWindow* window = GetWindow(WindowIdFromTransportId(window_id));
   if (window && ShouldRouteToWindowManager(window))
     window->set_can_focus(can_focus);
 }
 
+void WindowTreeImpl::SetPredefinedCursor(uint32_t change_id,
+                                         Id window_id,
+                                         mus::mojom::Cursor cursor_id) {
+  ServerWindow* window = GetWindow(WindowIdFromTransportId(window_id));
+
+  // Only the owner of the window can change the bounds.
+  bool success = window && access_policy_->CanSetCursorProperties(window);
+  if (success) {
+    Operation op(this, connection_manager_,
+                 OperationType::SET_WINDOW_PREDEFINED_CURSOR);
+    window->SetPredefinedCursor(cursor_id);
+  }
+  client_->OnChangeCompleted(change_id, success);
+}
+
 void WindowTreeImpl::WmResponse(uint32 change_id, bool response) {
   if (GetHost() && GetHost()->GetWindowTree() == this)
     connection_manager_->WindowManagerChangeCompleted(change_id, response);
diff --git a/components/mus/ws/window_tree_impl.h b/components/mus/ws/window_tree_impl.h
index 0a92f4f..7b1ee906d 100644
--- a/components/mus/ws/window_tree_impl.h
+++ b/components/mus/ws/window_tree_impl.h
@@ -95,10 +95,11 @@
                                   const gfx::Rect& old_bounds,
                                   const gfx::Rect& new_bounds,
                                   bool originated_change);
-  void ProcessClientAreaChanged(const ServerWindow* window,
-                                const gfx::Insets& old_client_area,
-                                const gfx::Insets& new_client_area,
-                                bool originated_change);
+  void ProcessClientAreaChanged(
+      const ServerWindow* window,
+      const gfx::Insets& new_client_area,
+      const std::vector<gfx::Rect>& new_additional_client_areas,
+      bool originated_change);
   void ProcessViewportMetricsChanged(const mojom::ViewportMetrics& old_metrics,
                                      const mojom::ViewportMetrics& new_metrics,
                                      bool originated_change);
@@ -121,6 +122,9 @@
   void ProcessWindowDeleted(const WindowId& window, bool originated_change);
   void ProcessWillChangeWindowVisibility(const ServerWindow* window,
                                          bool originated_change);
+  void ProcessCursorChanged(const ServerWindow* window,
+                            int32_t cursor_id,
+                            bool originated_change);
   void ProcessFocusChanged(const ServerWindow* old_focused_window,
                            const ServerWindow* new_focused_window);
   void ProcessTransientWindowAdded(const ServerWindow* window,
@@ -197,21 +201,17 @@
                  mojo::Map<mojo::String, mojo::Array<uint8_t>>
                      transport_properties) override;
   void DeleteWindow(uint32_t change_id, Id transport_window_id) override;
-  void AddWindow(Id parent_id,
-                 Id child_id,
-                 const mojo::Callback<void(bool)>& callback) override;
-  void RemoveWindowFromParent(
-      Id window_id,
-      const mojo::Callback<void(bool)>& callback) override;
+  void AddWindow(uint32_t change_id, Id parent_id, Id child_id) override;
+  void RemoveWindowFromParent(uint32_t change_id, Id window_id) override;
   void AddTransientWindow(uint32_t change_id,
                           Id window_id,
                           Id transient_window_id) override;
   void RemoveTransientWindowFromParent(uint32_t change_id,
                                        Id transient_window_id) override;
-  void ReorderWindow(Id window_id,
+  void ReorderWindow(uint32_t change_Id,
+                     Id window_id,
                      Id relative_window_id,
-                     mojom::OrderDirection direction,
-                     const mojo::Callback<void(bool)>& callback) override;
+                     mojom::OrderDirection direction) override;
   void GetWindowTree(
       Id window_id,
       const mojo::Callback<void(mojo::Array<mojom::WindowDataPtr>)>& callback)
@@ -234,15 +234,21 @@
              mojom::WindowTreeClientPtr client,
              uint32_t policy_bitmask,
              const EmbedCallback& callback) override;
-  void SetFocus(uint32_t window_id) override;
-  void SetCanFocus(uint32_t window_id, bool can_focus) override;
-  void SetWindowTextInputState(uint32_t window_id,
+  void SetFocus(uint32_t change_id, Id window_id) override;
+  void SetCanFocus(Id window_id, bool can_focus) override;
+  void SetPredefinedCursor(uint32_t change_id,
+                           Id window_id,
+                           mus::mojom::Cursor cursor_id) override;
+  void SetWindowTextInputState(Id window_id,
                                mojo::TextInputStatePtr state) override;
   void SetImeVisibility(Id transport_window_id,
                         bool visible,
                         mojo::TextInputStatePtr state) override;
   void OnWindowInputEventAck(uint32_t event_id) override;
-  void SetClientArea(Id transport_window_id, mojo::InsetsPtr insets) override;
+  void SetClientArea(
+      Id transport_window_id,
+      mojo::InsetsPtr insets,
+      mojo::Array<mojo::RectPtr> transport_additional_client_areas) override;
   void WmResponse(uint32 change_id, bool response) override;
 
   // AccessPolicyDelegate:
diff --git a/components/mus/ws/window_tree_unittest.cc b/components/mus/ws/window_tree_unittest.cc
index 3c9ab24..e8e545ae 100644
--- a/components/mus/ws/window_tree_unittest.cc
+++ b/components/mus/ws/window_tree_unittest.cc
@@ -77,9 +77,10 @@
     tracker_.OnWindowBoundsChanged(window, old_bounds.Pass(),
                                    new_bounds.Pass());
   }
-  void OnClientAreaChanged(uint32_t window_id,
-                           mojo::InsetsPtr old_client_area,
-                           mojo::InsetsPtr new_client_area) override {}
+  void OnClientAreaChanged(
+      uint32_t window_id,
+      mojo::InsetsPtr new_client_area,
+      mojo::Array<mojo::RectPtr> new_additional_client_areas) override {}
   void OnTransientWindowAdded(uint32_t window_id,
                               uint32_t transient_window_id) override {}
   void OnTransientWindowRemoved(uint32_t window_id,
@@ -124,6 +125,10 @@
   void OnWindowFocused(uint32_t focused_window_id) override {
     tracker_.OnWindowFocused(focused_window_id);
   }
+  void OnWindowPredefinedCursorChanged(uint32 window_id,
+                                       mojom::Cursor cursor_id) override {
+    tracker_.OnWindowPredefinedCursorChanged(window_id, cursor_id);
+  }
   void OnChangeCompleted(uint32_t change_id, bool success) override {}
   void WmSetBounds(uint32_t change_id,
                    Id window_id,
@@ -220,7 +225,8 @@
 // Empty implementation of DisplayManager.
 class TestDisplayManager : public DisplayManager {
  public:
-  TestDisplayManager() {}
+  explicit TestDisplayManager(int32_t* cursor_id_storage)
+      : cursor_id_storage_(cursor_id_storage) {}
   ~TestDisplayManager() override {}
 
   // DisplayManager:
@@ -237,6 +243,7 @@
                      const gfx::Rect& bounds) override {}
   void SetViewportSize(const gfx::Size& size) override {}
   void SetTitle(const base::string16& title) override {}
+  void SetCursorById(int32_t cursor) override { *cursor_id_storage_ = cursor; }
   const mojom::ViewportMetrics& GetViewportMetrics() override {
     return display_metrices_;
   }
@@ -247,22 +254,27 @@
  private:
   mojom::ViewportMetrics display_metrices_;
 
+  int32_t* cursor_id_storage_;
+
   DISALLOW_COPY_AND_ASSIGN(TestDisplayManager);
 };
 
 // Factory that dispenses TestDisplayManagers.
 class TestDisplayManagerFactory : public DisplayManagerFactory {
  public:
-  TestDisplayManagerFactory() {}
+  explicit TestDisplayManagerFactory(int32_t* cursor_id_storage)
+      : cursor_id_storage_(cursor_id_storage) {}
   ~TestDisplayManagerFactory() {}
   DisplayManager* CreateDisplayManager(
       mojo::ApplicationImpl* app_impl,
       const scoped_refptr<GpuState>& gpu_state,
       const scoped_refptr<mus::SurfacesState>& surfaces_state) override {
-    return new TestDisplayManager();
+    return new TestDisplayManager(cursor_id_storage_);
   }
 
  private:
+  int32_t* cursor_id_storage_;
+
   DISALLOW_COPY_AND_ASSIGN(TestDisplayManagerFactory);
 };
 
@@ -302,13 +314,32 @@
   return event.Pass();
 }
 
+EventPtr CreateMouseDownEvent(int x, int y) {
+  EventPtr event = CreatePointerDownEvent(x, y);
+  event->flags = static_cast<mus::mojom::EventFlags>(
+      event->flags | mojom::EVENT_FLAGS_LEFT_MOUSE_BUTTON);
+  event->pointer_data->kind = mojom::POINTER_KIND_MOUSE;
+  return event.Pass();
+}
+
+EventPtr CreateMouseUpEvent(int x, int y) {
+  EventPtr event = CreatePointerUpEvent(x, y);
+  event->flags = static_cast<mus::mojom::EventFlags>(
+      event->flags | mojom::EVENT_FLAGS_LEFT_MOUSE_BUTTON);
+  event->pointer_data->kind = mojom::POINTER_KIND_MOUSE;
+  return event.Pass();
+}
+
 }  // namespace
 
 // -----------------------------------------------------------------------------
 
 class WindowTreeTest : public testing::Test {
  public:
-  WindowTreeTest() : wm_client_(nullptr) {}
+  WindowTreeTest()
+      : wm_client_(nullptr),
+        cursor_id_(0),
+        display_manager_factory_(&cursor_id_) {}
   ~WindowTreeTest() override {}
 
   // WindowTreeImpl for the window manager.
@@ -327,6 +358,7 @@
   ConnectionManager* connection_manager() { return connection_manager_.get(); }
 
   TestWindowTreeClient* wm_client() { return wm_client_; }
+  int32_t cursor_id() { return cursor_id_; }
 
   TestWindowTreeHostConnection* host_connection() { return host_connection_; }
 
@@ -345,6 +377,11 @@
     AckPreviousEvent();
   }
 
+  // Embeds a child window to the root window. Shared setup between several of
+  // the unit tests.
+  void SetupEventTargeting(TestWindowTreeClient** out_client,
+                           ServerWindow** out_window);
+
  protected:
   // testing::Test:
   void SetUp() override {
@@ -367,6 +404,7 @@
  private:
   // TestWindowTreeClient that is used for the WM connection.
   TestWindowTreeClient* wm_client_;
+  int32_t cursor_id_;
   TestDisplayManagerFactory display_manager_factory_;
   TestConnectionManagerDelegate delegate_;
   TestWindowTreeHostConnection* host_connection_;
@@ -376,6 +414,52 @@
   DISALLOW_COPY_AND_ASSIGN(WindowTreeTest);
 };
 
+void WindowTreeTest::SetupEventTargeting(TestWindowTreeClient** out_client,
+                                         ServerWindow** out_window) {
+  const WindowId embed_window_id(wm_connection()->id(), 1);
+  EXPECT_TRUE(
+      wm_connection()->NewWindow(embed_window_id, ServerWindow::Properties()));
+  EXPECT_TRUE(wm_connection()->SetWindowVisibility(embed_window_id, true));
+  EXPECT_TRUE(
+      wm_connection()->AddWindow(*(wm_connection()->root()), embed_window_id));
+  host_connection()->window_tree_host()->root_window()->SetBounds(
+      gfx::Rect(0, 0, 100, 100));
+  mojom::WindowTreeClientPtr client;
+  mojo::InterfaceRequest<mojom::WindowTreeClient> client_request =
+      GetProxy(&client);
+  wm_client()->Bind(client_request.Pass());
+  ConnectionSpecificId connection_id = 0;
+  wm_connection()->Embed(embed_window_id, client.Pass(),
+                         mojom::WindowTree::ACCESS_POLICY_DEFAULT,
+                         &connection_id);
+  WindowTreeImpl* connection1 =
+      connection_manager()->GetConnectionWithRoot(embed_window_id);
+  ASSERT_TRUE(connection1 != nullptr);
+  ASSERT_NE(connection1, wm_connection());
+
+  connection_manager()
+      ->GetWindow(embed_window_id)
+      ->SetBounds(gfx::Rect(0, 0, 50, 50));
+
+  const WindowId child1(connection1->id(), 1);
+  EXPECT_TRUE(connection1->NewWindow(child1, ServerWindow::Properties()));
+  EXPECT_TRUE(connection1->AddWindow(embed_window_id, child1));
+  connection1->GetHost()->AddActivationParent(
+      WindowIdToTransportId(embed_window_id));
+
+  ServerWindow* v1 = connection1->GetWindow(child1);
+  v1->SetVisible(true);
+  v1->SetBounds(gfx::Rect(20, 20, 20, 20));
+  EnableHitTest(v1);
+
+  TestWindowTreeClient* embed_connection = last_window_tree_client();
+  embed_connection->tracker()->changes()->clear();
+  wm_client()->tracker()->changes()->clear();
+
+  *out_client = embed_connection;
+  *out_window = v1;
+}
+
 // Verifies focus correctly changes on pointer events.
 TEST_F(WindowTreeTest, FocusOnPointer) {
   const WindowId embed_window_id(wm_connection()->id(), 1);
@@ -464,46 +548,9 @@
 }
 
 TEST_F(WindowTreeTest, BasicInputEventTarget) {
-  const WindowId embed_window_id(wm_connection()->id(), 1);
-  EXPECT_TRUE(
-      wm_connection()->NewWindow(embed_window_id, ServerWindow::Properties()));
-  EXPECT_TRUE(wm_connection()->SetWindowVisibility(embed_window_id, true));
-  EXPECT_TRUE(
-      wm_connection()->AddWindow(*(wm_connection()->root()), embed_window_id));
-  host_connection()->window_tree_host()->root_window()->SetBounds(
-      gfx::Rect(0, 0, 100, 100));
-  mojom::WindowTreeClientPtr client;
-  mojo::InterfaceRequest<mojom::WindowTreeClient> client_request =
-      GetProxy(&client);
-  wm_client()->Bind(client_request.Pass());
-  ConnectionSpecificId connection_id = 0;
-  wm_connection()->Embed(embed_window_id,
-                         client.Pass(),
-                         mojom::WindowTree::ACCESS_POLICY_DEFAULT,
-                         &connection_id);
-  WindowTreeImpl* connection1 =
-      connection_manager()->GetConnectionWithRoot(embed_window_id);
-  ASSERT_TRUE(connection1 != nullptr);
-  ASSERT_NE(connection1, wm_connection());
-
-  connection_manager()
-      ->GetWindow(embed_window_id)
-      ->SetBounds(gfx::Rect(0, 0, 50, 50));
-
-  const WindowId child1(connection1->id(), 1);
-  EXPECT_TRUE(connection1->NewWindow(child1, ServerWindow::Properties()));
-  EXPECT_TRUE(connection1->AddWindow(embed_window_id, child1));
-  connection1->GetHost()->AddActivationParent(
-      WindowIdToTransportId(embed_window_id));
-
-  ServerWindow* v1 = connection1->GetWindow(child1);
-  v1->SetVisible(true);
-  v1->SetBounds(gfx::Rect(20, 20, 20, 20));
-  EnableHitTest(v1);
-
-  TestWindowTreeClient* embed_connection = last_window_tree_client();
-  embed_connection->tracker()->changes()->clear();
-  wm_client()->tracker()->changes()->clear();
+  TestWindowTreeClient* embed_connection = nullptr;
+  ServerWindow* out_window = nullptr;
+  EXPECT_NO_FATAL_FAILURE(SetupEventTargeting(&embed_connection, &out_window));
 
   // Send an event to |v1|. |embed_connection| should get the event, not
   // |wm_client|, since |v1| lives inside an embedded window.
@@ -518,6 +565,85 @@
             ChangesToDescription1(*embed_connection->tracker()->changes())[1]);
 }
 
+TEST_F(WindowTreeTest, CursorChangesWhenMouseOverWindowAndWindowSetsCursor) {
+  TestWindowTreeClient* embed_connection = nullptr;
+  ServerWindow* out_window = nullptr;
+  EXPECT_NO_FATAL_FAILURE(SetupEventTargeting(&embed_connection, &out_window));
+
+  // Like in BasicInputEventTarget, we send a pointer down event to be
+  // dispatched. This is only to place the mouse cursor over that window though.
+  DispatchEventAndAckImmediately(CreateMouseMoveEvent(21, 22));
+
+  out_window->SetPredefinedCursor(mojom::Cursor::CURSOR_IBEAM);
+
+  // Because the cursor is over the window when SetCursor was called, we should
+  // have immediately changed the cursor.
+  EXPECT_EQ(mojom::Cursor::CURSOR_IBEAM, cursor_id());
+}
+
+TEST_F(WindowTreeTest, CursorChangesWhenEnteringWindowWithDifferentCursor) {
+  TestWindowTreeClient* embed_connection = nullptr;
+  ServerWindow* out_window = nullptr;
+  EXPECT_NO_FATAL_FAILURE(SetupEventTargeting(&embed_connection, &out_window));
+
+  // Let's create a pointer event outside the window and then move the pointer
+  // inside.
+  DispatchEventAndAckImmediately(CreateMouseMoveEvent(5, 5));
+  out_window->SetPredefinedCursor(mojom::Cursor::CURSOR_IBEAM);
+  EXPECT_EQ(mojom::Cursor::CURSOR_NULL, cursor_id());
+
+  DispatchEventAndAckImmediately(CreateMouseMoveEvent(21, 22));
+  EXPECT_EQ(mojom::Cursor::CURSOR_IBEAM, cursor_id());
+}
+
+TEST_F(WindowTreeTest, TouchesDontChangeCursor) {
+  TestWindowTreeClient* embed_connection = nullptr;
+  ServerWindow* out_window = nullptr;
+  EXPECT_NO_FATAL_FAILURE(SetupEventTargeting(&embed_connection, &out_window));
+
+  // Let's create a pointer event outside the window and then move the pointer
+  // inside.
+  DispatchEventAndAckImmediately(CreateMouseMoveEvent(5, 5));
+  out_window->SetPredefinedCursor(mojom::Cursor::CURSOR_IBEAM);
+  EXPECT_EQ(mojom::Cursor::CURSOR_NULL, cursor_id());
+
+  // With a touch event, we shouldn't update the cursor.
+  DispatchEventAndAckImmediately(CreatePointerDownEvent(21, 22));
+  EXPECT_EQ(mojom::Cursor::CURSOR_NULL, cursor_id());
+}
+
+TEST_F(WindowTreeTest, DragOutsideWindow) {
+  TestWindowTreeClient* embed_connection = nullptr;
+  ServerWindow* out_window = nullptr;
+  EXPECT_NO_FATAL_FAILURE(SetupEventTargeting(&embed_connection, &out_window));
+
+  // Start with the cursor outside the window. Setting the cursor shouldn't
+  // change the cursor.
+  DispatchEventAndAckImmediately(CreateMouseMoveEvent(5, 5));
+  out_window->SetPredefinedCursor(mojom::Cursor::CURSOR_IBEAM);
+  EXPECT_EQ(mojom::Cursor::CURSOR_NULL, cursor_id());
+
+  // Move the pointer to the inside of the window
+  DispatchEventAndAckImmediately(CreateMouseMoveEvent(21, 22));
+  EXPECT_EQ(mojom::Cursor::CURSOR_IBEAM, cursor_id());
+
+  // Start the drag.
+  DispatchEventAndAckImmediately(CreateMouseDownEvent(21, 22));
+  EXPECT_EQ(mojom::Cursor::CURSOR_IBEAM, cursor_id());
+
+  // Move the cursor (mouse is still down) outside the window.
+  DispatchEventAndAckImmediately(CreateMouseMoveEvent(5, 5));
+  EXPECT_EQ(mojom::Cursor::CURSOR_IBEAM, cursor_id());
+
+  // Release the cursor. We should now adapt the cursor of the window
+  // underneath the pointer.
+  DispatchEventAndAckImmediately(CreateMouseUpEvent(5, 5));
+  EXPECT_EQ(mojom::Cursor::CURSOR_NULL, cursor_id());
+}
+
+// TODO(erg): Add tests for when programmatic changes to the window hierarchy
+// would cause the window that supplies the cursor to change.
+
 TEST_F(WindowTreeTest, EventAck) {
   const WindowId embed_window_id(wm_connection()->id(), 1);
   EXPECT_TRUE(
diff --git a/components/nacl/loader/nacl_main_platform_delegate_win.cc b/components/nacl/loader/nacl_main_platform_delegate_win.cc
index e4d0ad5..c0caa5e2 100644
--- a/components/nacl/loader/nacl_main_platform_delegate_win.cc
+++ b/components/nacl/loader/nacl_main_platform_delegate_win.cc
@@ -17,9 +17,6 @@
   // Cause advapi32 to load before the sandbox is turned on.
   unsigned int dummy_rand;
   rand_s(&dummy_rand);
-  // Warm up language subsystems before the sandbox is turned on.
-  ::GetUserDefaultLangID();
-  ::GetUserDefaultLCID();
 
   // Turn the sandbox on.
   target_services->LowerToken();
diff --git a/components/nacl/renderer/plugin/plugin.cc b/components/nacl/renderer/plugin/plugin.cc
index a790696..44ea7a4 100644
--- a/components/nacl/renderer/plugin/plugin.cc
+++ b/components/nacl/renderer/plugin/plugin.cc
@@ -9,6 +9,7 @@
 
 #include <string>
 
+#include "base/logging.h"
 #include "components/nacl/renderer/plugin/nacl_subprocess.h"
 #include "components/nacl/renderer/plugin/plugin_error.h"
 #include "components/nacl/renderer/plugin/service_runtime.h"
@@ -19,7 +20,6 @@
 #include "native_client/src/include/nacl_scoped_ptr.h"
 #include "native_client/src/include/portability.h"
 #include "native_client/src/include/portability_io.h"
-#include "native_client/src/shared/platform/nacl_check.h"
 #include "native_client/src/trusted/desc/nacl_desc_wrapper.h"
 #include "ppapi/c/pp_errors.h"
 #include "ppapi/cpp/module.h"
diff --git a/components/nacl/renderer/plugin/pnacl_coordinator.cc b/components/nacl/renderer/plugin/pnacl_coordinator.cc
index 052f289..28caad5 100644
--- a/components/nacl/renderer/plugin/pnacl_coordinator.cc
+++ b/components/nacl/renderer/plugin/pnacl_coordinator.cc
@@ -8,13 +8,13 @@
 #include <sstream>
 #include <utility>
 
+#include "base/logging.h"
 #include "components/nacl/renderer/plugin/plugin.h"
 #include "components/nacl/renderer/plugin/plugin_error.h"
 #include "components/nacl/renderer/plugin/pnacl_translate_thread.h"
 #include "components/nacl/renderer/plugin/service_runtime.h"
 #include "components/nacl/renderer/plugin/temporary_file.h"
 #include "native_client/src/include/portability_io.h"
-#include "native_client/src/shared/platform/nacl_check.h"
 #include "native_client/src/trusted/service_runtime/include/sys/stat.h"
 #include "ppapi/c/pp_bool.h"
 #include "ppapi/c/pp_errors.h"
diff --git a/components/nacl/renderer/plugin/pnacl_coordinator.h b/components/nacl/renderer/plugin/pnacl_coordinator.h
index 8c9f4a5..05dbaed 100644
--- a/components/nacl/renderer/plugin/pnacl_coordinator.h
+++ b/components/nacl/renderer/plugin/pnacl_coordinator.h
@@ -11,7 +11,6 @@
 #include "components/nacl/renderer/plugin/plugin_error.h"
 #include "components/nacl/renderer/plugin/pnacl_resources.h"
 #include "native_client/src/include/nacl_macros.h"
-#include "native_client/src/shared/platform/nacl_sync_raii.h"
 #include "native_client/src/shared/srpc/nacl_srpc.h"
 #include "native_client/src/trusted/desc/nacl_desc_wrapper.h"
 #include "ppapi/cpp/completion_callback.h"
diff --git a/components/nacl/renderer/plugin/pnacl_resources.cc b/components/nacl/renderer/plugin/pnacl_resources.cc
index 9e65d697..ac5a292 100644
--- a/components/nacl/renderer/plugin/pnacl_resources.cc
+++ b/components/nacl/renderer/plugin/pnacl_resources.cc
@@ -6,10 +6,10 @@
 
 #include <vector>
 
+#include "base/logging.h"
 #include "components/nacl/renderer/plugin/plugin.h"
 #include "components/nacl/renderer/plugin/utility.h"
 #include "native_client/src/include/portability_io.h"
-#include "native_client/src/shared/platform/nacl_check.h"
 #include "native_client/src/trusted/desc/nacl_desc_wrapper.h"
 #include "ppapi/c/pp_errors.h"
 
@@ -42,21 +42,14 @@
 
 const std::string& PnaclResources::GetUrl(ResourceType type) const {
   size_t index = static_cast<size_t>(type);
-  if (index < NUM_TYPES) {
-    return resources_[index].tool_name;
-  }
-  // TODO(jvoung): Use NOTREACHED() from base/logging.h once
-  // we are able to use base/logging.h without conflicting
-  // with NaCl macros.
-  DCHECK(false && "Index out of bounds");
-  // Return a dummy tool name.
+  DCHECK(index < NUM_TYPES);
   return resources_[index].tool_name;
 }
 
 PP_NaClFileInfo PnaclResources::TakeFileInfo(ResourceType type) {
   size_t index = static_cast<size_t>(type);
   if (index >= NUM_TYPES) {
-    DCHECK(false && "Index out of bounds");
+    NOTREACHED();
     return kInvalidNaClFileInfo;
   }
   PP_NaClFileInfo to_return = resources_[index].file_info;
diff --git a/components/nacl/renderer/plugin/pnacl_translate_thread.cc b/components/nacl/renderer/plugin/pnacl_translate_thread.cc
index 8b26a11..c7d64c7 100644
--- a/components/nacl/renderer/plugin/pnacl_translate_thread.cc
+++ b/components/nacl/renderer/plugin/pnacl_translate_thread.cc
@@ -13,6 +13,7 @@
 #include "components/nacl/renderer/plugin/temporary_file.h"
 #include "components/nacl/renderer/plugin/utility.h"
 #include "native_client/src/shared/platform/nacl_check.h"
+#include "native_client/src/shared/platform/nacl_sync_raii.h"
 #include "native_client/src/trusted/desc/nacl_desc_wrapper.h"
 #include "ppapi/cpp/var.h"
 
diff --git a/components/nacl/renderer/plugin/sel_ldr_launcher_chrome.cc b/components/nacl/renderer/plugin/sel_ldr_launcher_chrome.cc
index ece90f0..305c386 100644
--- a/components/nacl/renderer/plugin/sel_ldr_launcher_chrome.cc
+++ b/components/nacl/renderer/plugin/sel_ldr_launcher_chrome.cc
@@ -3,8 +3,9 @@
 // found in the LICENSE file.
 
 #include "components/nacl/renderer/plugin/sel_ldr_launcher_chrome.h"
+
+#include "base/logging.h"
 #include "native_client/src/include/nacl_macros.h"
-#include "native_client/src/shared/platform/nacl_check.h"
 
 namespace plugin {
 
diff --git a/components/nacl/renderer/plugin/service_runtime.cc b/components/nacl/renderer/plugin/service_runtime.cc
index fd01c3b..016c6bf 100644
--- a/components/nacl/renderer/plugin/service_runtime.cc
+++ b/components/nacl/renderer/plugin/service_runtime.cc
@@ -23,7 +23,6 @@
 #include "native_client/src/include/portability_io.h"
 #include "native_client/src/include/portability_string.h"
 #include "native_client/src/public/imc_types.h"
-#include "native_client/src/shared/platform/nacl_check.h"
 #include "native_client/src/shared/platform/nacl_log.h"
 #include "native_client/src/trusted/nonnacl_util/sel_ldr_launcher.h"
 #include "native_client/src/trusted/service_runtime/nacl_error_code.h"
diff --git a/components/nacl/renderer/plugin/temporary_file.cc b/components/nacl/renderer/plugin/temporary_file.cc
index 95e8a52..9fc1a68 100644
--- a/components/nacl/renderer/plugin/temporary_file.cc
+++ b/components/nacl/renderer/plugin/temporary_file.cc
@@ -4,10 +4,10 @@
 
 #include "components/nacl/renderer/plugin/temporary_file.h"
 
+#include "base/logging.h"
 #include "components/nacl/renderer/plugin/plugin.h"
 #include "components/nacl/renderer/plugin/utility.h"
 #include "native_client/src/include/portability_io.h"
-#include "native_client/src/shared/platform/nacl_check.h"
 #include "native_client/src/trusted/service_runtime/include/sys/stat.h"
 #include "ppapi/c/private/pp_file_handle.h"
 #include "ppapi/cpp/core.h"
diff --git a/components/nacl/renderer/plugin/utility.cc b/components/nacl/renderer/plugin/utility.cc
index c994f73..6a31850 100644
--- a/components/nacl/renderer/plugin/utility.cc
+++ b/components/nacl/renderer/plugin/utility.cc
@@ -11,7 +11,6 @@
 #include "components/nacl/renderer/plugin/utility.h"
 #include "native_client/src/include/portability_io.h"
 #include "native_client/src/include/portability_process.h"
-#include "native_client/src/shared/platform/nacl_check.h"
 #include "ppapi/cpp/module.h"
 
 namespace plugin {
diff --git a/components/plugins/renderer/webview_plugin.h b/components/plugins/renderer/webview_plugin.h
index 75d079c..74b4b1b 100644
--- a/components/plugins/renderer/webview_plugin.h
+++ b/components/plugins/renderer/webview_plugin.h
@@ -110,13 +110,6 @@
   void didFinishLoading() override;
   void didFailLoading(const blink::WebURLError& error) override;
 
-  // Called in response to WebPluginContainer::loadFrameRequest
-  void didFinishLoadingFrameRequest(const blink::WebURL& url,
-                                    void* notifyData) override {}
-  void didFailLoadingFrameRequest(const blink::WebURL& url,
-                                  void* notify_data,
-                                  const blink::WebURLError& error) override {}
-
   // WebViewClient methods:
   bool acceptsLoadDrops() override;
 
diff --git a/components/safe_browsing_db/util.cc b/components/safe_browsing_db/util.cc
index 9507075a..c34c161 100644
--- a/components/safe_browsing_db/util.cc
+++ b/components/safe_browsing_db/util.cc
@@ -143,32 +143,35 @@
 
 std::string Unescape(const std::string& url) {
   std::string unescaped_str(url);
-  std::string old_unescaped_str;
   const int kMaxLoopIterations = 1024;
+  size_t old_size = 0;
   int loop_var = 0;
   do {
-    old_unescaped_str = unescaped_str;
+    old_size = unescaped_str.size();
     unescaped_str = net::UnescapeURLComponent(
-        old_unescaped_str, net::UnescapeRule::SPOOFING_AND_CONTROL_CHARS |
-                               net::UnescapeRule::SPACES |
-                               net::UnescapeRule::URL_SPECIAL_CHARS);
-  } while (unescaped_str != old_unescaped_str && ++loop_var <=
-           kMaxLoopIterations);
+        unescaped_str, net::UnescapeRule::SPOOFING_AND_CONTROL_CHARS |
+                           net::UnescapeRule::SPACES |
+                           net::UnescapeRule::URL_SPECIAL_CHARS);
+  } while (old_size != unescaped_str.size() &&
+           ++loop_var <= kMaxLoopIterations);
 
   return unescaped_str;
 }
 
 std::string Escape(const std::string& url) {
   std::string escaped_str;
+  // The escaped string is larger so allocate double the length to reduce the
+  // chance of the string being grown.
+  escaped_str.reserve(url.length() * 2);
   const char* kHexString = "0123456789ABCDEF";
   for (size_t i = 0; i < url.length(); i++) {
     unsigned char c = static_cast<unsigned char>(url[i]);
     if (c <= ' ' || c > '~' || c == '#' || c == '%') {
-      escaped_str.push_back('%');
-      escaped_str.push_back(kHexString[c >> 4]);
-      escaped_str.push_back(kHexString[c & 0xf]);
+      escaped_str += '%';
+      escaped_str += kHexString[c >> 4];
+      escaped_str += kHexString[c & 0xf];
     } else {
-      escaped_str.push_back(c);
+      escaped_str += c;
     }
   }
 
@@ -230,22 +233,21 @@
                         &parsed);
 
   // 3. In hostname, remove all leading and trailing dots.
-  const std::string host =
-      (parsed.host.len > 0)
-          ? url_unescaped_str.substr(parsed.host.begin, parsed.host.len)
-          : std::string();
-  std::string host_without_end_dots;
-  base::TrimString(host, ".", &host_without_end_dots);
+  base::StringPiece host;
+  if (parsed.host.len > 0)
+    host.set(url_unescaped_str.data() + parsed.host.begin, parsed.host.len);
+
+  base::StringPiece host_without_end_dots =
+      base::TrimString(host, ".", base::TrimPositions::TRIM_ALL);
 
   // 4. In hostname, replace consecutive dots with a single dot.
   std::string host_without_consecutive_dots(RemoveConsecutiveChars(
       host_without_end_dots, '.'));
 
   // 5. In path, replace runs of consecutive slashes with a single slash.
-  std::string path =
-      (parsed.path.len > 0)
-          ? url_unescaped_str.substr(parsed.path.begin, parsed.path.len)
-          : std::string();
+  base::StringPiece path;
+  if (parsed.path.len > 0)
+    path.set(url_unescaped_str.data() + parsed.path.begin, parsed.path.len);
   std::string path_without_consecutive_slash(RemoveConsecutiveChars(path, '/'));
 
   url::Replacements<char> hp_replacements;
diff --git a/components/scheduler/BUILD.gn b/components/scheduler/BUILD.gn
index a22b377..83d83e59 100644
--- a/components/scheduler/BUILD.gn
+++ b/components/scheduler/BUILD.gn
@@ -43,12 +43,12 @@
     "base/task_queue_manager_delegate_for_test.h",
     "base/task_queue_manager_unittest.cc",
     "base/task_queue_selector_unittest.cc",
-    "base/task_queue_sets_unittest.cc",
     "base/test_always_fail_time_source.cc",
     "base/test_always_fail_time_source.h",
     "base/test_time_source.cc",
     "base/test_time_source.h",
     "base/time_domain_unittest.cc",
+    "base/work_queue_sets_unittest.cc",
     "child/idle_helper_unittest.cc",
     "child/scheduler_helper_unittest.cc",
     "child/scheduler_tqm_delegate_for_test.cc",
diff --git a/components/scheduler/base/lazy_now.h b/components/scheduler/base/lazy_now.h
index 34c659b..959a245 100644
--- a/components/scheduler/base/lazy_now.h
+++ b/components/scheduler/base/lazy_now.h
@@ -6,6 +6,7 @@
 #define COMPONENTS_SCHEDULER_BASE_LAZY_NOW_H_
 
 #include "base/time/time.h"
+#include "components/scheduler/scheduler_export.h"
 
 namespace base {
 class TickClock;
@@ -15,7 +16,7 @@
 
 // Now() is somewhat expensive so it makes sense not to call Now() unless we
 // really need to.
-class LazyNow {
+class SCHEDULER_EXPORT LazyNow {
  public:
   explicit LazyNow(base::TimeTicks now) : tick_clock_(nullptr), now_(now) {
     DCHECK(!now.is_null());
diff --git a/components/scheduler/base/real_time_domain.cc b/components/scheduler/base/real_time_domain.cc
index d894eca..5f0b3e1 100644
--- a/components/scheduler/base/real_time_domain.cc
+++ b/components/scheduler/base/real_time_domain.cc
@@ -6,29 +6,28 @@
 
 #include "base/bind.h"
 #include "components/scheduler/base/task_queue_impl.h"
+#include "components/scheduler/base/task_queue_manager.h"
 #include "components/scheduler/base/task_queue_manager_delegate.h"
 
 namespace scheduler {
 
-RealTimeDomain::RealTimeDomain() : TimeDomain(nullptr), weak_factory_(this) {}
+RealTimeDomain::RealTimeDomain()
+    : TimeDomain(nullptr), task_queue_manager_(nullptr) {}
 
 RealTimeDomain::~RealTimeDomain() {}
 
 void RealTimeDomain::OnRegisterWithTaskQueueManager(
-    TaskQueueManagerDelegate* task_queue_manager_delegate,
-    base::Closure do_work_closure) {
-  task_queue_manager_delegate_ = task_queue_manager_delegate;
-  do_work_closure_ = do_work_closure;
-  DCHECK(task_queue_manager_delegate_);
+    TaskQueueManager* task_queue_manager) {
+  task_queue_manager_ = task_queue_manager;
+  DCHECK(task_queue_manager_);
 }
 
 LazyNow RealTimeDomain::CreateLazyNow() {
-  DCHECK(task_queue_manager_delegate_);
-  return LazyNow(task_queue_manager_delegate_);
+  return task_queue_manager_->CreateLazyNow();
 }
 
 void RealTimeDomain::RequestWakeup(LazyNow* lazy_now, base::TimeDelta delay) {
-  PostWrappedDoWork(lazy_now->Now(), lazy_now->Now() + delay);
+  task_queue_manager_->MaybeScheduleDelayedWork(FROM_HERE, lazy_now, delay);
 }
 
 bool RealTimeDomain::MaybeAdvanceTime() {
@@ -36,33 +35,15 @@
   if (!NextScheduledRunTime(&next_run_time))
     return false;
 
-  DCHECK(task_queue_manager_delegate_);
-  base::TimeTicks now = task_queue_manager_delegate_->NowTicks();
-  if (now >= next_run_time)
+  LazyNow lazy_now = task_queue_manager_->CreateLazyNow();
+  if (lazy_now.Now() >= next_run_time)
     return true;
 
-  PostWrappedDoWork(now, next_run_time);
+  task_queue_manager_->MaybeScheduleDelayedWork(FROM_HERE, &lazy_now,
+                                                next_run_time - lazy_now.Now());
   return false;
 }
 
-void RealTimeDomain::PostWrappedDoWork(base::TimeTicks now,
-                                       base::TimeTicks run_time) {
-  DCHECK_GE(run_time, now);
-  DCHECK(task_queue_manager_delegate_);
-  if (pending_wakeups_.insert(run_time).second) {
-    task_queue_manager_delegate_->PostDelayedTask(
-        FROM_HERE,
-        base::Bind(&RealTimeDomain::WrappedDoWorkTask,
-                   weak_factory_.GetWeakPtr(), run_time),
-        run_time - now);
-  }
-}
-
-void RealTimeDomain::WrappedDoWorkTask(base::TimeTicks run_time) {
-  pending_wakeups_.erase(run_time);
-  do_work_closure_.Run();
-}
-
 void RealTimeDomain::AsValueIntoInternal(
     base::trace_event::TracedValue* state) const {}
 
diff --git a/components/scheduler/base/real_time_domain.h b/components/scheduler/base/real_time_domain.h
index 82525637..ab20d80 100644
--- a/components/scheduler/base/real_time_domain.h
+++ b/components/scheduler/base/real_time_domain.h
@@ -12,7 +12,6 @@
 #include "components/scheduler/scheduler_export.h"
 
 namespace scheduler {
-class TaskQueueManagerDelegate;
 
 class SCHEDULER_EXPORT RealTimeDomain : public TimeDomain {
  public:
@@ -26,20 +25,13 @@
 
  protected:
   void OnRegisterWithTaskQueueManager(
-      TaskQueueManagerDelegate* task_queue_manager_delegate,
-      base::Closure do_work_closure) override;
+      TaskQueueManager* task_queue_manager) override;
   void RequestWakeup(LazyNow* lazy_now, base::TimeDelta delay) override;
   void AsValueIntoInternal(
       base::trace_event::TracedValue* state) const override;
 
  private:
-  void PostWrappedDoWork(base::TimeTicks now, base::TimeTicks run_time);
-  void WrappedDoWorkTask(base::TimeTicks run_time);
-
-  TaskQueueManagerDelegate* task_queue_manager_delegate_;  // NOT OWNED
-  std::set<base::TimeTicks> pending_wakeups_;
-  base::Closure do_work_closure_;
-  base::WeakPtrFactory<RealTimeDomain> weak_factory_;
+  TaskQueueManager* task_queue_manager_;  // NOT OWNED
 
   DISALLOW_COPY_AND_ASSIGN(RealTimeDomain);
 };
diff --git a/components/scheduler/base/task_queue.cc b/components/scheduler/base/task_queue.cc
index 24aadb7..b5f7827 100644
--- a/components/scheduler/base/task_queue.cc
+++ b/components/scheduler/base/task_queue.cc
@@ -3,12 +3,3 @@
 // found in the LICENSE file.
 
 #include "components/scheduler/base/task_queue.h"
-
-namespace scheduler {
-
-bool TaskQueue::HasPendingImmediateTask() const {
-  QueueState state = GetQueueState();
-  return state == QueueState::NEEDS_PUMPING || state == QueueState::HAS_WORK;
-}
-
-}  // namespace scheduler
diff --git a/components/scheduler/base/task_queue.h b/components/scheduler/base/task_queue.h
index fbbbc25..a9964d9 100644
--- a/components/scheduler/base/task_queue.h
+++ b/components/scheduler/base/task_queue.h
@@ -74,22 +74,6 @@
     FIRST_WAKEUP_POLICY = CAN_WAKE_OTHER_QUEUES,
   };
 
-  enum class QueueState {
-    // A queue in the EMPTY state is empty and has no tasks in either the
-    // work or incoming task queue.
-    EMPTY,
-    // A queue in the NEEDS_PUMPING state has no tasks in the work task queue,
-    // but has tasks in the incoming task queue which can be pumped to make them
-    // runnable.
-    NEEDS_PUMPING,
-    // A queue in the HAS_WORK state has tasks in the work task queue which
-    // are runnable.
-    HAS_WORK,
-    // The work and incomming queues are empty but there is delayed work
-    // scheduled.
-    NO_IMMEDIATE_WORK,
-  };
-
   // Options for constructing a TaskQueue. Once set the |name|,
   // |should_monitor_quiescence| and |wakeup_policy| are immutable. The
   // |pump_policy| can be mutated with |SetPumpPolicy()|.
@@ -141,16 +125,16 @@
   // thread this TaskQueue was created by.
   virtual bool IsQueueEnabled() const = 0;
 
-  // Returns true if there no tasks in either the work or incoming task queue.
-  // This method ignores delayed tasks that are scheduled to run in the future.
-  // Note that this function involves taking a lock, so calling it has some
-  // overhead. NOTE this must be called on the thread this TaskQueue was created
-  // by.
-  virtual bool HasPendingImmediateTask() const;
+  // Returns true if the queue is completely empty.
+  virtual bool IsEmpty() const = 0;
 
-  // Returns the QueueState. Note that this function involves taking a lock, so
-  // calling it has some overhead.
-  virtual QueueState GetQueueState() const = 0;
+  // Returns true if the queue has work that's ready to execute now, or if it
+  // would have if the queue was pumped. NOTE this must be called on the thread
+  // this TaskQueue was created by.
+  virtual bool HasPendingImmediateWork() const = 0;
+
+  // Returns true if tasks can't run now but could if the queue was pumped.
+  virtual bool NeedsPumping() const = 0;
 
   // Can be called on any thread.
   virtual const char* GetName() const = 0;
@@ -170,7 +154,12 @@
   // This function only needs to be called if automatic pumping is disabled.
   // By default automatic pumping is enabled for all queues. NOTE this must be
   // called on the thread this TaskQueue was created by.
-  virtual void PumpQueue() = 0;
+  //
+  // The |may_post_dowork| parameter controls whether or not PumpQueue calls
+  // TaskQueueManager::MaybeScheduleImmediateWork.
+  // TODO(alexclarke): Add a base::RunLoop observer so we can get rid of
+  // |may_post_dowork|.
+  virtual void PumpQueue(bool may_post_dowork) = 0;
 
   // These functions can only be called on the same thread that the task queue
   // manager executes its tasks on.
diff --git a/components/scheduler/base/task_queue_impl.cc b/components/scheduler/base/task_queue_impl.cc
index f58fabd..1d2b249 100644
--- a/components/scheduler/base/task_queue_impl.cc
+++ b/components/scheduler/base/task_queue_impl.cc
@@ -7,6 +7,7 @@
 #include "components/scheduler/base/task_queue_manager.h"
 #include "components/scheduler/base/task_queue_manager_delegate.h"
 #include "components/scheduler/base/time_domain.h"
+#include "components/scheduler/base/work_queue.h"
 
 namespace scheduler {
 namespace internal {
@@ -24,7 +25,7 @@
           disabled_by_default_tracing_category),
       disabled_by_default_verbose_tracing_category_(
           disabled_by_default_verbose_tracing_category),
-      main_thread_only_(task_queue_manager),
+      main_thread_only_(task_queue_manager, this),
       wakeup_policy_(spec.wakeup_policy),
       should_monitor_quiescence_(spec.should_monitor_quiescence),
       should_notify_observers_(spec.should_notify_observers) {
@@ -52,6 +53,7 @@
 
 TaskQueueImpl::Task::Task(const tracked_objects::Location& posted_from,
                           const base::Closure& task,
+                          base::TimeTicks desired_run_time,
                           int sequence_number,
                           bool nestable)
     : PendingTask(posted_from, task, base::TimeTicks(), nestable),
@@ -59,6 +61,22 @@
       enqueue_order_set_(false),
 #endif
       enqueue_order_(0) {
+  delayed_run_time = desired_run_time;
+  sequence_num = sequence_number;
+}
+
+TaskQueueImpl::Task::Task(const tracked_objects::Location& posted_from,
+                          const base::Closure& task,
+                          base::TimeTicks desired_run_time,
+                          int sequence_number,
+                          bool nestable,
+                          int enqueue_order)
+    : PendingTask(posted_from, task, base::TimeTicks(), nestable),
+#ifndef NDEBUG
+      enqueue_order_set_(true),
+#endif
+      enqueue_order_(enqueue_order) {
+  delayed_run_time = desired_run_time;
   sequence_num = sequence_number;
 }
 
@@ -72,9 +90,17 @@
 TaskQueueImpl::AnyThread::~AnyThread() {}
 
 TaskQueueImpl::MainThreadOnly::MainThreadOnly(
-    TaskQueueManager* task_queue_manager)
+    TaskQueueManager* task_queue_manager,
+    TaskQueueImpl* task_queue)
     : task_queue_manager(task_queue_manager),
-      set_index(0) {}
+      delayed_work_queue(
+          new WorkQueue(task_queue_manager->selector_.delayed_task_queue_sets(),
+                        task_queue,
+                        "delayed")),
+      immediate_work_queue(new WorkQueue(
+          task_queue_manager->selector_.immediate_task_queue_sets(),
+          task_queue,
+          "immediate")) {}
 
 TaskQueueImpl::MainThreadOnly::~MainThreadOnly() {}
 
@@ -89,9 +115,10 @@
 
   any_thread().task_queue_manager = nullptr;
   main_thread_only().task_queue_manager = nullptr;
-  any_thread().delayed_task_queue = std::priority_queue<Task>();
-  any_thread().incoming_queue = std::queue<Task>();
-  main_thread_only().work_queue = std::queue<Task>();
+  any_thread().delayed_incoming_queue = std::priority_queue<Task>();
+  any_thread().immediate_incoming_queue = std::queue<Task>();
+  main_thread_only().immediate_work_queue->Clear();
+  main_thread_only().delayed_work_queue->Clear();
 }
 
 bool TaskQueueImpl::RunsTasksOnCurrentThread() const {
@@ -135,40 +162,61 @@
     base::TimeTicks desired_run_time,
     TaskType task_type) {
   DCHECK(any_thread().task_queue_manager);
-  Task pending_task(from_here, task,
-                    any_thread().task_queue_manager->GetNextSequenceNumber(),
-                    task_type != TaskType::NON_NESTABLE);
-  any_thread().task_queue_manager->DidQueueTask(pending_task);
-
+  int sequence_number =
+      any_thread().task_queue_manager->GetNextSequenceNumber();
   if (!desired_run_time.is_null()) {
-    pending_task.delayed_run_time = std::max(lazy_now->Now(), desired_run_time);
-    // TODO(alexclarke): consider emplace() when C++11 library features allowed.
-    any_thread().delayed_task_queue.push(pending_task);
-    TraceQueueSize(true);
-    // Schedule a later call to MoveReadyDelayedTasksToIncomingQueue.
-    if (base::PlatformThread::CurrentId() == thread_id_) {
-      any_thread().time_domain->ScheduleDelayedWork(this, desired_run_time,
-                                                    lazy_now);
-    } else {
-      // NOTE posting a delayed task from a different thread is not expected to
-      // be common. This pathway is less optimal than perhaps it could be
-      // because it causes two main thread tasks to be run.  Should this
-      // assumption prove to be false in future, we may need to revisit this.
-      Task thread_hop_task(
-          FROM_HERE, base::Bind(&TaskQueueImpl::ScheduleDelayedWorkTask, this,
-                                any_thread().time_domain, desired_run_time),
-          any_thread().task_queue_manager->GetNextSequenceNumber(), true);
-      thread_hop_task.set_enqueue_order(thread_hop_task.sequence_num);
-      any_thread().task_queue_manager->DidQueueTask(thread_hop_task);
-      EnqueueTaskLocked(thread_hop_task);
-    }
-    return true;
+    PushOntoDelayedIncomingQueueLocked(
+        Task(from_here, task, std::max(lazy_now->Now(), desired_run_time),
+             sequence_number, task_type != TaskType::NON_NESTABLE),
+        lazy_now);
+  } else {
+    PushOntoImmediateIncomingQueueLocked(
+        Task(from_here, task, base::TimeTicks(), sequence_number,
+             task_type != TaskType::NON_NESTABLE, sequence_number));
   }
-  pending_task.set_enqueue_order(pending_task.sequence_num);
-  EnqueueTaskLocked(pending_task);
   return true;
 }
 
+void TaskQueueImpl::PushOntoDelayedIncomingQueueLocked(
+    const Task&& pending_task,
+    LazyNow* lazy_now) {
+  any_thread().task_queue_manager->DidQueueTask(pending_task);
+  any_thread().delayed_incoming_queue.push(pending_task);
+
+  // Schedule a later call to MoveReadyDelayedTasksToDelayedWorkQueue.
+  if (base::PlatformThread::CurrentId() == thread_id_) {
+    any_thread().time_domain->ScheduleDelayedWork(
+        this, pending_task.delayed_run_time, lazy_now);
+    TraceQueueSize(true);
+  } else {
+    // NOTE posting a delayed task from a different thread is not expected to
+    // be common. This pathway is less optimal than perhaps it could be
+    // because it causes two main thread tasks to be run.  Should this
+    // assumption prove to be false in future, we may need to revisit this.
+    int thread_hop_task_sequence_number =
+        any_thread().task_queue_manager->GetNextSequenceNumber();
+    PushOntoImmediateIncomingQueueLocked(Task(
+        FROM_HERE,
+        base::Bind(&TaskQueueImpl::ScheduleDelayedWorkTask, this,
+                   any_thread().time_domain, pending_task.delayed_run_time),
+        base::TimeTicks(), thread_hop_task_sequence_number, false,
+        thread_hop_task_sequence_number));
+  }
+}
+
+void TaskQueueImpl::PushOntoImmediateIncomingQueueLocked(
+    const Task&& pending_task) {
+  if (any_thread().immediate_incoming_queue.empty())
+    any_thread().time_domain->RegisterAsUpdatableTaskQueue(this);
+  if (any_thread().pump_policy == PumpPolicy::AUTO &&
+      any_thread().immediate_incoming_queue.empty()) {
+    any_thread().task_queue_manager->MaybeScheduleImmediateWork(FROM_HERE);
+  }
+  any_thread().task_queue_manager->DidQueueTask(pending_task);
+  any_thread().immediate_incoming_queue.push(pending_task);
+  TraceQueueSize(true);
+}
+
 void TaskQueueImpl::ScheduleDelayedWorkTask(TimeDomain* time_domain,
                                             base::TimeTicks desired_run_time) {
   DCHECK(main_thread_checker_.CalledOnValidThread());
@@ -176,27 +224,6 @@
   time_domain->ScheduleDelayedWork(this, desired_run_time, &lazy_now);
 }
 
-void TaskQueueImpl::MoveReadyDelayedTasksToIncomingQueue(LazyNow* lazy_now) {
-  base::AutoLock lock(any_thread_lock_);
-  if (!any_thread().task_queue_manager)
-    return;
-
-  MoveReadyDelayedTasksToIncomingQueueLocked(lazy_now);
-}
-
-void TaskQueueImpl::MoveReadyDelayedTasksToIncomingQueueLocked(
-    LazyNow* lazy_now) {
-  // Enqueue all delayed tasks that should be running now.
-  while (!any_thread().delayed_task_queue.empty() &&
-         any_thread().delayed_task_queue.top().delayed_run_time <=
-             lazy_now->Now()) {
-    // TODO(alexclarke): consider std::move() when allowed.
-    EnqueueDelayedTaskLocked(any_thread().delayed_task_queue.top());
-    any_thread().delayed_task_queue.pop();
-  }
-  TraceQueueSize(true);
-}
-
 bool TaskQueueImpl::IsQueueEnabled() const {
   if (!main_thread_only().task_queue_manager)
     return false;
@@ -204,21 +231,41 @@
   return main_thread_only().task_queue_manager->selector_.IsQueueEnabled(this);
 }
 
-TaskQueue::QueueState TaskQueueImpl::GetQueueState() const {
-  if (!main_thread_only().work_queue.empty())
-    return QueueState::HAS_WORK;
-
-  {
-    base::AutoLock lock(any_thread_lock_);
-    if (any_thread().incoming_queue.empty()) {
-      if (any_thread().delayed_task_queue.empty())
-        return QueueState::EMPTY;
-      else
-        return QueueState::NO_IMMEDIATE_WORK;
-    } else {
-      return QueueState::NEEDS_PUMPING;
-    }
+bool TaskQueueImpl::IsEmpty() const {
+  if (!main_thread_only().delayed_work_queue->Empty() ||
+      !main_thread_only().immediate_work_queue->Empty()) {
+    return false;
   }
+
+  base::AutoLock lock(any_thread_lock_);
+  return any_thread().immediate_incoming_queue.empty() &&
+         any_thread().delayed_incoming_queue.empty();
+}
+
+bool TaskQueueImpl::HasPendingImmediateWork() const {
+  if (!main_thread_only().delayed_work_queue->Empty() ||
+      !main_thread_only().immediate_work_queue->Empty()) {
+    return true;
+  }
+
+  return NeedsPumping();
+}
+
+bool TaskQueueImpl::NeedsPumping() const {
+  if (!main_thread_only().immediate_work_queue->Empty())
+    return false;
+
+  base::AutoLock lock(any_thread_lock_);
+  if (!any_thread().immediate_incoming_queue.empty())
+    return true;
+
+  // If there's no immediate Incoming work then we only need pumping if there
+  // is a delayed task that should be running now.
+  if (any_thread().delayed_incoming_queue.empty())
+    return false;
+
+  return any_thread().delayed_incoming_queue.top().delayed_run_time <=
+         any_thread().time_domain->CreateLazyNow().Now();
 }
 
 bool TaskQueueImpl::TaskIsOlderThanQueuedTasks(const Task* task) {
@@ -228,13 +275,20 @@
   if (!task)
     return true;
 
-  // Return false if there are no task in the incoming queue.
-  if (any_thread().incoming_queue.empty())
+  // Return false if task is newer than the oldest immediate task.
+  if (!any_thread().immediate_incoming_queue.empty() &&
+      task->enqueue_order() >
+          any_thread().immediate_incoming_queue.front().enqueue_order()) {
     return false;
+  }
 
-  const TaskQueueImpl::Task& oldest_queued_task =
-      any_thread().incoming_queue.front();
-  return task->enqueue_order() < oldest_queued_task.enqueue_order();
+  int enqueue_order;
+  if (!main_thread_only().delayed_work_queue->GetFrontTaskEnqueueOrder(
+          &enqueue_order)) {
+    return true;
+  }
+
+  return task->enqueue_order() < enqueue_order;
 }
 
 bool TaskQueueImpl::ShouldAutoPumpQueueLocked(bool should_trigger_wakeup,
@@ -244,41 +298,50 @@
   if (any_thread().pump_policy == PumpPolicy::AFTER_WAKEUP &&
       (!should_trigger_wakeup || TaskIsOlderThanQueuedTasks(previous_task)))
     return false;
-  if (any_thread().incoming_queue.empty())
-    return false;
   return true;
 }
 
-void TaskQueueImpl::UpdateWorkQueue(LazyNow* lazy_now,
-                                    bool should_trigger_wakeup,
-                                    const Task* previous_task) {
-  DCHECK(main_thread_only().work_queue.empty());
-  base::AutoLock lock(any_thread_lock_);
-  if (!ShouldAutoPumpQueueLocked(should_trigger_wakeup, previous_task))
-    return;
-  MoveReadyDelayedTasksToIncomingQueueLocked(lazy_now);
-  std::swap(main_thread_only().work_queue, any_thread().incoming_queue);
-  // |any_thread().incoming_queue| is now empty so TimeDomain::UpdateQueues
-  // no longer needs to consider this queue for reloading.
-  any_thread().time_domain->UnregisterAsUpdatableTaskQueue(this);
-  if (!main_thread_only().work_queue.empty()) {
-    DCHECK(any_thread().task_queue_manager);
-    any_thread().task_queue_manager->selector_.GetTaskQueueSets()->OnPushQueue(
-        this);
-    TraceQueueSize(true);
+void TaskQueueImpl::MoveReadyDelayedTasksToDelayedWorkQueueLocked(
+    LazyNow* lazy_now) {
+  // Enqueue all delayed tasks that should be running now.
+  while (!any_thread().delayed_incoming_queue.empty() &&
+         any_thread().delayed_incoming_queue.top().delayed_run_time <=
+             lazy_now->Now()) {
+    main_thread_only().delayed_work_queue->PushAndSetEnqueueOrder(
+        std::move(any_thread().delayed_incoming_queue.top()),
+        any_thread().task_queue_manager->GetNextSequenceNumber());
+    any_thread().delayed_incoming_queue.pop();
   }
 }
 
-TaskQueueImpl::Task TaskQueueImpl::TakeTaskFromWorkQueue() {
-  // TODO(alexclarke): consider std::move() when allowed.
-  Task pending_task = main_thread_only().work_queue.front();
-  main_thread_only().work_queue.pop();
-  DCHECK(main_thread_only().task_queue_manager);
-  main_thread_only()
-      .task_queue_manager->selector_.GetTaskQueueSets()
-      ->OnPopQueue(this);
-  TraceQueueSize(false);
-  return pending_task;
+void TaskQueueImpl::UpdateDelayedWorkQueue(LazyNow* lazy_now,
+                                           bool should_trigger_wakeup,
+                                           const Task* previous_task) {
+  base::AutoLock lock(any_thread_lock_);
+  if (!any_thread().task_queue_manager)
+    return;
+  if (!ShouldAutoPumpQueueLocked(should_trigger_wakeup, previous_task))
+    return;
+  MoveReadyDelayedTasksToDelayedWorkQueueLocked(lazy_now);
+  TraceQueueSize(true);
+}
+
+void TaskQueueImpl::UpdateImmediateWorkQueue(bool should_trigger_wakeup,
+                                             const Task* previous_task) {
+  DCHECK(main_thread_only().immediate_work_queue->Empty());
+  base::AutoLock lock(any_thread_lock_);
+  if (!any_thread().task_queue_manager)
+    return;
+  if (!ShouldAutoPumpQueueLocked(should_trigger_wakeup, previous_task))
+    return;
+
+  main_thread_only().immediate_work_queue->Swap(
+      any_thread().immediate_incoming_queue);
+
+  // |any_thread().immediate_incoming_queue| is now empty so
+  // TimeDomain::UpdateQueues no longer needs to consider this queue for
+  // reloading.
+  any_thread().time_domain->UnregisterAsUpdatableTaskQueue(this);
 }
 
 void TaskQueueImpl::TraceQueueSize(bool is_locked) const {
@@ -292,101 +355,59 @@
   else
     any_thread_lock_.AssertAcquired();
   TRACE_COUNTER1(disabled_by_default_tracing_category_, GetName(),
-                 any_thread().incoming_queue.size() +
-                     main_thread_only().work_queue.size() +
-                     any_thread().delayed_task_queue.size());
+                 any_thread().immediate_incoming_queue.size() +
+                     main_thread_only().immediate_work_queue->Size() +
+                     main_thread_only().delayed_work_queue->Size() +
+                     any_thread().delayed_incoming_queue.size());
   if (!is_locked)
     any_thread_lock_.Release();
 }
 
-void TaskQueueImpl::EnqueueTaskLocked(const Task& pending_task) {
-  if (!any_thread().task_queue_manager)
-    return;
-  if (any_thread().incoming_queue.empty())
-    any_thread().time_domain->RegisterAsUpdatableTaskQueue(this);
-  if (any_thread().pump_policy == PumpPolicy::AUTO &&
-      any_thread().incoming_queue.empty()) {
-    any_thread().task_queue_manager->MaybePostDoWorkOnMainRunner();
-  }
-  // TODO(alexclarke): consider std::move() when allowed.
-  any_thread().incoming_queue.push(pending_task);
-  TraceQueueSize(true);
-}
-
-// TODO(alexclarke): Consider merging EnqueueTaskLocked &
-//  EnqueueDelayedTaskLocked.
-void TaskQueueImpl::EnqueueDelayedTaskLocked(const Task& pending_task) {
-  if (!any_thread().task_queue_manager)
-    return;
-  if (any_thread().incoming_queue.empty())
-    any_thread().time_domain->RegisterAsUpdatableTaskQueue(this);
-  // TODO(alexclarke): consider std::move() when allowed.
-  any_thread().incoming_queue.push(pending_task);
-  any_thread().incoming_queue.back().set_enqueue_order(
-      any_thread().task_queue_manager->GetNextSequenceNumber());
-  TraceQueueSize(true);
-}
-
 void TaskQueueImpl::SetPumpPolicy(PumpPolicy pump_policy) {
   base::AutoLock lock(any_thread_lock_);
   if (pump_policy == PumpPolicy::AUTO &&
       any_thread().pump_policy != PumpPolicy::AUTO) {
-    PumpQueueLocked();
+    PumpQueueLocked(true);
   }
   any_thread().pump_policy = pump_policy;
 }
 
-void TaskQueueImpl::PumpQueueLocked() {
-  if (!any_thread().task_queue_manager)
+void TaskQueueImpl::PumpQueueLocked(bool may_post_dowork) {
+  TaskQueueManager* task_queue_manager = any_thread().task_queue_manager;
+  if (!task_queue_manager)
     return;
 
   LazyNow lazy_now(any_thread().time_domain->CreateLazyNow());
-  MoveReadyDelayedTasksToIncomingQueueLocked(&lazy_now);
+  MoveReadyDelayedTasksToDelayedWorkQueueLocked(&lazy_now);
 
-  bool was_empty = main_thread_only().work_queue.empty();
-  while (!any_thread().incoming_queue.empty()) {
-    // TODO(alexclarke): consider std::move() when allowed.
-    main_thread_only().work_queue.push(any_thread().incoming_queue.front());
-    any_thread().incoming_queue.pop();
+  while (!any_thread().immediate_incoming_queue.empty()) {
+    main_thread_only().immediate_work_queue->Push(
+        std::move(any_thread().immediate_incoming_queue.front()));
+    any_thread().immediate_incoming_queue.pop();
   }
-  // |incoming_queue| is now empty so TimeDomain::UpdateQueues no longer needs
-  // to consider this queue for reloading.
+
+  // |immediate_incoming_queue| is now empty so TimeDomain::UpdateQueues no
+  // longer needs to consider this queue for reloading.
   any_thread().time_domain->UnregisterAsUpdatableTaskQueue(this);
-  if (!main_thread_only().work_queue.empty()) {
-    if (was_empty) {
-      any_thread()
-          .task_queue_manager->selector_.GetTaskQueueSets()
-          ->OnPushQueue(this);
-    }
-    any_thread().task_queue_manager->MaybePostDoWorkOnMainRunner();
+
+  if (main_thread_only().immediate_work_queue->Empty() &&
+      main_thread_only().delayed_work_queue->Empty()) {
+    return;
   }
+
+  if (may_post_dowork)
+    task_queue_manager->MaybeScheduleImmediateWork(FROM_HERE);
 }
 
-void TaskQueueImpl::PumpQueue() {
+void TaskQueueImpl::PumpQueue(bool may_post_dowork) {
   base::AutoLock lock(any_thread_lock_);
-  PumpQueueLocked();
+  PumpQueueLocked(may_post_dowork);
 }
 
 const char* TaskQueueImpl::GetName() const {
   return name_;
 }
 
-bool TaskQueueImpl::GetWorkQueueFrontTaskEnqueueOrder(
-    int* enqueue_order) const {
-  if (main_thread_only().work_queue.empty())
-    return false;
-  *enqueue_order = main_thread_only().work_queue.front().enqueue_order();
-  return true;
-}
-
-void TaskQueueImpl::PushTaskOntoWorkQueueForTest(const Task& task) {
-  main_thread_only().work_queue.push(task);
-}
-
-void TaskQueueImpl::PopTaskFromWorkQueueForTest() {
-  main_thread_only().work_queue.pop();
-}
-
 void TaskQueueImpl::SetQueuePriority(QueuePriority priority) {
   if (!main_thread_only().task_queue_manager)
     return;
@@ -454,23 +475,32 @@
   bool verbose_tracing_enabled = false;
   TRACE_EVENT_CATEGORY_GROUP_ENABLED(
       disabled_by_default_verbose_tracing_category_, &verbose_tracing_enabled);
-  state->SetInteger("incoming_queue_size", any_thread().incoming_queue.size());
-  state->SetInteger("work_queue_size", main_thread_only().work_queue.size());
-  state->SetInteger("delayed_task_queue_size",
-                    any_thread().delayed_task_queue.size());
+  state->SetInteger("immediate_incoming_queue_size",
+                    any_thread().immediate_incoming_queue.size());
+  state->SetInteger("delayed_incoming_queue_size",
+                    any_thread().delayed_incoming_queue.size());
+  state->SetInteger("immediate_work_queue_size",
+                    main_thread_only().immediate_work_queue->Size());
+  state->SetInteger("delayed_work_queue_size",
+                    main_thread_only().delayed_work_queue->Size());
   if (verbose_tracing_enabled) {
-    state->BeginArray("incoming_queue");
-    QueueAsValueInto(any_thread().incoming_queue, state);
+    state->BeginArray("immediate_incoming_queue");
+    QueueAsValueInto(any_thread().immediate_incoming_queue, state);
     state->EndArray();
-    state->BeginArray("work_queue");
-    QueueAsValueInto(main_thread_only().work_queue, state);
+    state->BeginArray("delayed_work_queue");
+    main_thread_only().delayed_work_queue->AsValueInto(state);
     state->EndArray();
-    state->BeginArray("delayed_task_queue");
-    QueueAsValueInto(any_thread().delayed_task_queue, state);
+    state->BeginArray("immediate_work_queue");
+    main_thread_only().immediate_work_queue->AsValueInto(state);
+    state->EndArray();
+    state->BeginArray("delayed_incoming_queue");
+    QueueAsValueInto(any_thread().delayed_incoming_queue, state);
     state->EndArray();
   }
-  state->SetString("priority", PriorityToString(static_cast<QueuePriority>(
-                                   main_thread_only().set_index)));
+  state->SetString(
+      "priority",
+      PriorityToString(static_cast<QueuePriority>(
+          main_thread_only().immediate_work_queue->work_queue_set_index())));
   state->EndDictionary();
 }
 
@@ -546,10 +576,5 @@
   state->EndDictionary();
 }
 
-size_t TaskQueueImpl::IncomingQueueSizeForTest() const {
-  base::AutoLock lock(any_thread_lock_);
-  return any_thread().incoming_queue.size();
-}
-
 }  // namespace internal
 }  // namespace scheduler
diff --git a/components/scheduler/base/task_queue_impl.h b/components/scheduler/base/task_queue_impl.h
index aa846394..7f85f9a 100644
--- a/components/scheduler/base/task_queue_impl.h
+++ b/components/scheduler/base/task_queue_impl.h
@@ -20,6 +20,9 @@
 class TaskQueueManager;
 
 namespace internal {
+class WorkQueue;
+class WorkQueueSets;
+
 class SCHEDULER_EXPORT TaskQueueImpl final : public TaskQueue {
  public:
   TaskQueueImpl(TaskQueueManager* task_queue_manager,
@@ -33,9 +36,17 @@
     Task();
     Task(const tracked_objects::Location& posted_from,
          const base::Closure& task,
+         base::TimeTicks desired_run_time,
          int sequence_number,
          bool nestable);
 
+    Task(const tracked_objects::Location& posted_from,
+         const base::Closure& task,
+         base::TimeTicks desired_run_time,
+         int sequence_number,
+         bool nestable,
+         int enqueue_order);
+
     int enqueue_order() const {
 #ifndef NDEBUG
       DCHECK(enqueue_order_set_);
@@ -57,7 +68,7 @@
 #endif
     // Similar to sequence number, but the |enqueue_order| is set by
     // EnqueueTasksLocked and is not initially defined for delayed tasks until
-    // they are enqueued on the |incoming_queue_|.
+    // they are enqueued on the |immediate_incoming_queue_|.
     int enqueue_order_;
   };
 
@@ -72,21 +83,22 @@
                                   base::TimeDelta delay) override;
 
   bool IsQueueEnabled() const override;
-  QueueState GetQueueState() const override;
+  bool IsEmpty() const override;
+  bool HasPendingImmediateWork() const override;
+  bool NeedsPumping() const override;
   void SetQueuePriority(QueuePriority priority) override;
-  void PumpQueue() override;
+  void PumpQueue(bool may_post_dowork) override;
   void SetPumpPolicy(PumpPolicy pump_policy) override;
   void AddTaskObserver(base::MessageLoop::TaskObserver* task_observer) override;
   void RemoveTaskObserver(
       base::MessageLoop::TaskObserver* task_observer) override;
   void SetTimeDomain(TimeDomain* time_domain) override;
 
-  void UpdateWorkQueue(LazyNow* lazy_now,
-                       bool should_trigger_wakeup,
-                       const Task* previous_task);
-  Task TakeTaskFromWorkQueue();
-
-  std::queue<Task>& work_queue() { return main_thread_only().work_queue; }
+  void UpdateImmediateWorkQueue(bool should_trigger_wakeup,
+                                const Task* previous_task);
+  void UpdateDelayedWorkQueue(LazyNow* lazy_now,
+                              bool should_trigger_wakeup,
+                              const Task* previous_task);
 
   WakeupPolicy wakeup_policy() const {
     DCHECK(main_thread_checker_.CalledOnValidThread());
@@ -97,19 +109,6 @@
 
   void AsValueInto(base::trace_event::TracedValue* state) const;
 
-  size_t get_task_queue_set_index() const {
-    return main_thread_only().set_index;
-  }
-
-  void set_task_queue_set_index(size_t set_index) {
-    main_thread_only().set_index = set_index;
-  }
-
-  // If the work queue isn't empty, |enqueue_order| gets set to the enqueue
-  // order of the front task and the function returns true.  Otherwise the
-  // function returns false.
-  bool GetWorkQueueFrontTaskEnqueueOrder(int* enqueue_order) const;
-
   bool GetQuiescenceMonitored() const { return should_monitor_quiescence_; }
   bool GetShouldNotifyObservers() const {
     return should_notify_observers_;
@@ -118,20 +117,6 @@
   void NotifyWillProcessTask(const base::PendingTask& pending_task);
   void NotifyDidProcessTask(const base::PendingTask& pending_task);
 
-  // Delayed task posted to the underlying run loop, which locks
-  // |any_thread_lock_| and calls MoveReadyDelayedTasksToIncomingQueueLocked to
-  // process dealyed tasks that need to be run now.  Thread safe, but in
-  // practice it's always called from the main thread.
-  void MoveReadyDelayedTasksToIncomingQueue(LazyNow* lazy_now);
-
-  // Test support functions.  These should not be used in production code.
-  void PushTaskOntoWorkQueueForTest(const Task& task);
-  void PopTaskFromWorkQueueForTest();
-  size_t WorkQueueSizeForTest() const {
-    return main_thread_only().work_queue.size();
-  }
-  size_t IncomingQueueSizeForTest() const;
-
   // Can be called on any thread.
   static const char* PumpPolicyToString(TaskQueue::PumpPolicy pump_policy);
 
@@ -142,7 +127,25 @@
   // Can be called on any thread.
   static const char* PriorityToString(TaskQueue::QueuePriority priority);
 
+  WorkQueue* delayed_work_queue() {
+    return main_thread_only().delayed_work_queue.get();
+  }
+
+  const WorkQueue* delayed_work_queue() const {
+    return main_thread_only().delayed_work_queue.get();
+  }
+
+  WorkQueue* immediate_work_queue() {
+    return main_thread_only().immediate_work_queue.get();
+  }
+
+  const WorkQueue* immediate_work_queue() const {
+    return main_thread_only().immediate_work_queue.get();
+  }
+
  private:
+  friend class WorkQueue;
+
   enum class TaskType {
     NORMAL,
     NON_NESTABLE,
@@ -159,21 +162,23 @@
     // locked before accessing from other threads.
     TaskQueueManager* task_queue_manager;
 
-    std::queue<Task> incoming_queue;
+    std::queue<Task> immediate_incoming_queue;
+    std::priority_queue<Task> delayed_incoming_queue;
     PumpPolicy pump_policy;
-    std::priority_queue<Task> delayed_task_queue;
     TimeDomain* time_domain;
   };
 
   struct MainThreadOnly {
-    MainThreadOnly(TaskQueueManager* task_queue_manager);
+    MainThreadOnly(TaskQueueManager* task_queue_manager,
+                   TaskQueueImpl* task_queue);
     ~MainThreadOnly();
 
     // Another copy of TaskQueueManager for lock-free access from the main
     // thread. See description inside struct AnyThread for details.
     TaskQueueManager* task_queue_manager;
 
-    std::queue<Task> work_queue;
+    scoped_ptr<WorkQueue> delayed_work_queue;
+    scoped_ptr<WorkQueue> immediate_work_queue;
     base::ObserverList<base::MessageLoop::TaskObserver> task_observers;
     size_t set_index;
   };
@@ -192,23 +197,25 @@
   void ScheduleDelayedWorkTask(TimeDomain* time_domain,
                                base::TimeTicks desired_run_time);
 
-  // Enqueues any delayed tasks which should be run now on the incoming_queue_.
-  // Must be called with |any_thread_lock_| locked.
-  void MoveReadyDelayedTasksToIncomingQueueLocked(LazyNow* lazy_now);
+  // Enqueues any delayed tasks which should be run now on the
+  // |delayed_work_queue|. Must be called with |any_thread_lock_| locked.
+  void MoveReadyDelayedTasksToDelayedWorkQueueLocked(LazyNow* lazy_now);
 
-  void PumpQueueLocked();
+  void MoveReadyImmediateTasksToImmediateWorkQueueLocked();
+
+  void PumpQueueLocked(bool may_post_dowork);
   bool TaskIsOlderThanQueuedTasks(const Task* task);
   bool ShouldAutoPumpQueueLocked(bool should_trigger_wakeup,
                                  const Task* previous_task);
 
-  // Push the task onto the |incoming_queue_| and for auto pumped queues it
-  // calls MaybePostDoWorkOnMainRunner if the incomming queue was empty.
-  void EnqueueTaskLocked(const Task& pending_task);
+  // Push the task onto the |delayed_incoming_queue|
+  void PushOntoDelayedIncomingQueueLocked(const Task&& pending_task,
+                                          LazyNow* lazy_now);
 
-  // Push the task onto the |incoming_queue_| and allocates an
-  // enqueue_order for it based on |enqueue_order_policy|.  Does not call
-  // MaybePostDoWorkOnMainRunner!
-  void EnqueueDelayedTaskLocked(const Task& pending_task);
+  // Push the task onto the |immediate_incoming_queue| and for auto pumped
+  // queues it calls MaybePostDoWorkOnMainRunner if the Incoming queue was
+  // empty.
+  void PushOntoImmediateIncomingQueueLocked(const Task&& pending_task);
 
   void TraceQueueSize(bool is_locked) const;
   static void QueueAsValueInto(const std::queue<Task>& queue,
diff --git a/components/scheduler/base/task_queue_manager.cc b/components/scheduler/base/task_queue_manager.cc
index ec478db..6fec6e0 100644
--- a/components/scheduler/base/task_queue_manager.cc
+++ b/components/scheduler/base/task_queue_manager.cc
@@ -12,7 +12,8 @@
 #include "components/scheduler/base/task_queue_impl.h"
 #include "components/scheduler/base/task_queue_manager_delegate.h"
 #include "components/scheduler/base/task_queue_selector.h"
-#include "components/scheduler/base/task_queue_sets.h"
+#include "components/scheduler/base/work_queue.h"
+#include "components/scheduler/base/work_queue_sets.h"
 
 namespace scheduler {
 
@@ -24,7 +25,6 @@
     : real_time_domain_(new RealTimeDomain()),
       delegate_(delegate),
       task_was_run_on_quiescence_monitored_queue_(false),
-      pending_dowork_count_(0),
       work_batch_size_(1),
       tracing_category_(tracing_category),
       disabled_by_default_tracing_category_(
@@ -39,10 +39,12 @@
                                      "TaskQueueManager", this);
   selector_.SetTaskQueueSelectorObserver(this);
 
-  decrement_pending_and_do_work_closure_ =
-      base::Bind(&TaskQueueManager::DoWork, weak_factory_.GetWeakPtr(), true);
-  do_work_closure_ =
-      base::Bind(&TaskQueueManager::DoWork, weak_factory_.GetWeakPtr(), false);
+  from_main_thread_immediate_do_work_closure_ =
+      base::Bind(&TaskQueueManager::DoWork, weak_factory_.GetWeakPtr(),
+                 base::TimeTicks(), true);
+  from_other_thread_immediate_do_work_closure_ =
+      base::Bind(&TaskQueueManager::DoWork, weak_factory_.GetWeakPtr(),
+                 base::TimeTicks(), false);
 
   // TODO(alexclarke): Change this to be a parameter that's passed in.
   RegisterTimeDomain(real_time_domain_.get());
@@ -60,8 +62,7 @@
 
 void TaskQueueManager::RegisterTimeDomain(TimeDomain* time_domain) {
   time_domains_.insert(time_domain);
-  time_domain->OnRegisterWithTaskQueueManager(delegate_.get(),
-                                              do_work_closure_);
+  time_domain->OnRegisterWithTaskQueueManager(this);
 }
 
 void TaskQueueManager::UnregisterTimeDomain(TimeDomain* time_domain) {
@@ -117,27 +118,50 @@
   }
 }
 
-void TaskQueueManager::MaybePostDoWorkOnMainRunner() {
+void TaskQueueManager::MaybeScheduleImmediateWork(
+    const tracked_objects::Location& from_here) {
   bool on_main_thread = delegate_->BelongsToCurrentThread();
+  // De-duplicate DoWork posts.
   if (on_main_thread) {
-    // We only want one pending DoWork posted from the main thread, or we risk
-    // an explosion of pending DoWorks which could starve out everything else.
-    if (pending_dowork_count_ > 0) {
+    if (!main_thread_pending_wakeups_.insert(base::TimeTicks()).second) {
       return;
     }
-    pending_dowork_count_++;
-    delegate_->PostTask(FROM_HERE, decrement_pending_and_do_work_closure_);
+    delegate_->PostTask(from_here, from_main_thread_immediate_do_work_closure_);
   } else {
-    delegate_->PostTask(FROM_HERE, do_work_closure_);
+    base::AutoLock lock(other_thread_lock_);
+    if (!other_thread_pending_wakeups_.insert(base::TimeTicks()).second)
+      return;
+    delegate_->PostTask(from_here,
+                        from_other_thread_immediate_do_work_closure_);
   }
 }
 
-void TaskQueueManager::DoWork(bool decrement_pending_dowork_count) {
-  if (decrement_pending_dowork_count) {
-    pending_dowork_count_--;
-    DCHECK_GE(pending_dowork_count_, 0);
-  }
+void TaskQueueManager::MaybeScheduleDelayedWork(
+    const tracked_objects::Location& from_here,
+    LazyNow* lazy_now,
+    base::TimeDelta delay) {
   DCHECK(main_thread_checker_.CalledOnValidThread());
+  DCHECK_GE(delay, base::TimeDelta());
+  base::TimeTicks run_time = lazy_now->Now() + delay;
+  // De-duplicate DoWork posts.
+  if (!main_thread_pending_wakeups_.insert(run_time).second)
+    return;
+  delegate_->PostDelayedTask(
+      from_here, base::Bind(&TaskQueueManager::DoWork,
+                            weak_factory_.GetWeakPtr(), run_time, true),
+      delay);
+}
+
+void TaskQueueManager::DoWork(base::TimeTicks run_time, bool from_main_thread) {
+  DCHECK(main_thread_checker_.CalledOnValidThread());
+  TRACE_EVENT1(tracing_category_, "TaskQueueManager::DoWork",
+               "from_main_thread", from_main_thread);
+  if (from_main_thread) {
+    main_thread_pending_wakeups_.erase(run_time);
+  } else {
+    base::AutoLock lock(other_thread_lock_);
+    other_thread_pending_wakeups_.erase(run_time);
+  }
 
   if (!delegate_->IsNested())
     queues_to_delete_.clear();
@@ -148,11 +172,12 @@
 
   internal::TaskQueueImpl::Task previous_task;
   for (int i = 0; i < work_batch_size_; i++) {
-    internal::TaskQueueImpl* queue;
-    if (!SelectQueueToService(&queue))
+    internal::WorkQueue* work_queue;
+    if (!SelectWorkQueueToService(&work_queue)) {
       break;
+    }
 
-    switch (ProcessTaskFromWorkQueue(queue, &previous_task)) {
+    switch (ProcessTaskFromWorkQueue(work_queue, &previous_task)) {
       case ProcessTaskResult::DEFERRED:
         // If a task was deferred, try again with another task. Note that this
         // means deferred tasks (i.e. non-nestable tasks) will never trigger
@@ -163,7 +188,7 @@
       case ProcessTaskResult::TASK_QUEUE_MANAGER_DELETED:
         return;  // The TaskQueueManager got deleted, we must bail out.
     }
-    bool should_trigger_wakeup = queue->wakeup_policy() ==
+    bool should_trigger_wakeup = work_queue->task_queue()->wakeup_policy() ==
                                  TaskQueue::WakeupPolicy::CAN_WAKE_OTHER_QUEUES;
     UpdateWorkQueues(should_trigger_wakeup, &previous_task);
 
@@ -177,7 +202,7 @@
   // when there's no more work left to be done, rather than posting a
   // continuation task.
   if (!selector_.EnabledWorkQueuesEmpty() || TryAdvanceTimeDomains()) {
-    MaybePostDoWorkOnMainRunner();
+    MaybeScheduleImmediateWork(FROM_HERE);
   } else {
     // Tell the task runner we have no more work.
     delegate_->OnNoMoreImmediateWork();
@@ -192,12 +217,12 @@
   return can_advance;
 }
 
-bool TaskQueueManager::SelectQueueToService(
-    internal::TaskQueueImpl** out_queue) {
-  bool should_run = selector_.SelectQueueToService(out_queue);
+bool TaskQueueManager::SelectWorkQueueToService(
+    internal::WorkQueue** out_work_queue) {
+  bool should_run = selector_.SelectWorkQueueToService(out_work_queue);
   TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(
       disabled_by_default_tracing_category_, "TaskQueueManager", this,
-      AsValueWithSelectorResult(should_run, *out_queue));
+      AsValueWithSelectorResult(should_run, *out_work_queue));
   return should_run;
 }
 
@@ -207,16 +232,17 @@
 }
 
 TaskQueueManager::ProcessTaskResult TaskQueueManager::ProcessTaskFromWorkQueue(
-    internal::TaskQueueImpl* queue,
+    internal::WorkQueue* work_queue,
     internal::TaskQueueImpl::Task* out_previous_task) {
   DCHECK(main_thread_checker_.CalledOnValidThread());
   scoped_refptr<DeletionSentinel> protect(deletion_sentinel_);
-  // TODO(alexclarke): consider std::move() when allowed.
-  internal::TaskQueueImpl::Task pending_task = queue->TakeTaskFromWorkQueue();
+  internal::TaskQueueImpl* queue = work_queue->task_queue();
 
   if (queue->GetQuiescenceMonitored())
     task_was_run_on_quiescence_monitored_queue_ = true;
 
+  internal::TaskQueueImpl::Task pending_task =
+      work_queue->TakeTaskFromWorkQueue();
   if (!pending_task.nestable && delegate_->IsNested()) {
     // Defer non-nestable work to the main task runner.  NOTE these tasks can be
     // arbitrarily delayed so the additional delay should not be a problem.
@@ -290,10 +316,14 @@
   return task_sequence_num_.GetNext();
 }
 
+LazyNow TaskQueueManager::CreateLazyNow() const {
+  return LazyNow(delegate_.get());
+}
+
 scoped_refptr<base::trace_event::ConvertableToTraceFormat>
 TaskQueueManager::AsValueWithSelectorResult(
     bool should_run,
-    internal::TaskQueueImpl* selected_queue) const {
+    internal::WorkQueue* selected_work_queue) const {
   DCHECK(main_thread_checker_.CalledOnValidThread());
   scoped_refptr<base::trace_event::TracedValue> state =
       new base::trace_event::TracedValue();
@@ -304,8 +334,11 @@
   state->BeginDictionary("selector");
   selector_.AsValueInto(state.get());
   state->EndDictionary();
-  if (should_run)
-    state->SetString("selected_queue", selected_queue->GetName());
+  if (should_run) {
+    state->SetString("selected_queue",
+                     selected_work_queue->task_queue()->GetName());
+    state->SetString("work_queue_name", selected_work_queue->name());
+  }
 
   state->BeginArray("time_domains");
   for (auto& time_domain : time_domains_)
@@ -317,8 +350,10 @@
 void TaskQueueManager::OnTaskQueueEnabled(internal::TaskQueueImpl* queue) {
   DCHECK(main_thread_checker_.CalledOnValidThread());
   // Only schedule DoWork if there's something to do.
-  if (!queue->work_queue().empty())
-    MaybePostDoWorkOnMainRunner();
+  if (!queue->immediate_work_queue()->Empty() ||
+      !queue->delayed_work_queue()->Empty()) {
+    MaybeScheduleImmediateWork(FROM_HERE);
+  }
 }
 
 }  // namespace scheduler
diff --git a/components/scheduler/base/task_queue_manager.h b/components/scheduler/base/task_queue_manager.h
index f7090bd..b9705547 100644
--- a/components/scheduler/base/task_queue_manager.h
+++ b/components/scheduler/base/task_queue_manager.h
@@ -62,6 +62,19 @@
                    const char* disabled_by_default_verbose_tracing_category);
   ~TaskQueueManager() override;
 
+  // Requests that a task to process work is posted on the main task runner.
+  // These tasks are de-duplicated in two buckets: main-thread and all other
+  // threads.  This distinction is done to reduce the overehead from locks, we
+  // assume the main-thread path will be hot.
+  void MaybeScheduleImmediateWork(const tracked_objects::Location& from_here);
+
+  // Requests that a delayed task to process work is posted on the main task
+  // runner. These delayed tasks are de-duplicated. Must be called on the thread
+  // this class was created on.
+  void MaybeScheduleDelayedWork(const tracked_objects::Location& from_here,
+                                LazyNow* lazy_now,
+                                base::TimeDelta delay);
+
   // Set the number of tasks executed in a single invocation of the task queue
   // manager. Increasing the batch size can reduce the overhead of yielding
   // back to the main message loop -- at the cost of potentially delaying other
@@ -105,6 +118,8 @@
 
   RealTimeDomain* real_time_domain() const { return real_time_domain_.get(); }
 
+  LazyNow CreateLazyNow() const;
+
  private:
   friend class LazyNow;
   friend class internal::TaskQueueImpl;
@@ -128,13 +143,8 @@
   // Called by the task queue to register a new pending task.
   void DidQueueTask(const internal::TaskQueueImpl::Task& pending_task);
 
-  // Post a task to call DoWork() on the main task runner.  Only one pending
-  // DoWork is allowed from the main thread, to prevent an explosion of pending
-  // DoWorks.
-  void MaybePostDoWorkOnMainRunner();
-
   // Use the selector to choose a pending task and run it.
-  void DoWork(bool decrement_pending_dowork_count);
+  void DoWork(base::TimeTicks run_time, bool from_main_thread);
 
   // Delayed Tasks with run_times <= Now() are enqueued onto the work queue.
   // Reloads any empty work queues which have automatic pumping enabled and
@@ -147,7 +157,7 @@
   // Chooses the next work queue to service. Returns true if |out_queue|
   // indicates the queue from which the next task should be run, false to
   // avoid running any tasks.
-  bool SelectQueueToService(internal::TaskQueueImpl** out_queue);
+  bool SelectWorkQueueToService(internal::WorkQueue** out_work_queue);
 
   // Runs a single nestable task from the |queue|. On exit, |out_task| will
   // contain the task which was executed. Non-nestable task are reposted on the
@@ -158,7 +168,7 @@
     TASK_QUEUE_MANAGER_DELETED
   };
   ProcessTaskResult ProcessTaskFromWorkQueue(
-      internal::TaskQueueImpl* queue,
+      internal::WorkQueue* work_queue,
       internal::TaskQueueImpl::Task* out_previous_task);
 
   bool RunsTasksOnCurrentThread() const;
@@ -172,7 +182,7 @@
 
   scoped_refptr<base::trace_event::ConvertableToTraceFormat>
   AsValueWithSelectorResult(bool should_run,
-                            internal::TaskQueueImpl* selected_queue) const;
+                            internal::WorkQueue* selected_work_queue) const;
 
   std::set<TimeDomain*> time_domains_;
   scoped_ptr<RealTimeDomain> real_time_domain_;
@@ -191,14 +201,18 @@
   scoped_refptr<TaskQueueManagerDelegate> delegate_;
   internal::TaskQueueSelector selector_;
 
-  base::Closure decrement_pending_and_do_work_closure_;
-  base::Closure do_work_closure_;
+  base::Closure from_main_thread_immediate_do_work_closure_;
+  base::Closure from_other_thread_immediate_do_work_closure_;
 
   bool task_was_run_on_quiescence_monitored_queue_;
 
-  // The pending_dowork_count_ is only tracked on the main thread since that's
-  // where re-entrant problems happen.
-  int pending_dowork_count_;
+  // To reduce locking overhead we track pending calls to DoWork seperatly for
+  // the main thread and other threads.
+  std::set<base::TimeTicks> main_thread_pending_wakeups_;
+
+  // Protects |other_thread_pending_wakeups_|.
+  mutable base::Lock other_thread_lock_;
+  std::set<base::TimeTicks> other_thread_pending_wakeups_;
 
   int work_batch_size_;
 
diff --git a/components/scheduler/base/task_queue_manager_perftest.cc b/components/scheduler/base/task_queue_manager_perftest.cc
index dcdb5069..c1c69309 100644
--- a/components/scheduler/base/task_queue_manager_perftest.cc
+++ b/components/scheduler/base/task_queue_manager_perftest.cc
@@ -10,7 +10,7 @@
 #include "components/scheduler/base/task_queue_impl.h"
 #include "components/scheduler/base/task_queue_manager_delegate_for_test.h"
 #include "components/scheduler/base/task_queue_selector.h"
-#include "components/scheduler/base/task_queue_sets.h"
+#include "components/scheduler/base/work_queue_sets.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/perf/perf_test.h"
 
diff --git a/components/scheduler/base/task_queue_manager_unittest.cc b/components/scheduler/base/task_queue_manager_unittest.cc
index f1d9dc4..6396d362 100644
--- a/components/scheduler/base/task_queue_manager_unittest.cc
+++ b/components/scheduler/base/task_queue_manager_unittest.cc
@@ -14,10 +14,11 @@
 #include "components/scheduler/base/task_queue_impl.h"
 #include "components/scheduler/base/task_queue_manager_delegate_for_test.h"
 #include "components/scheduler/base/task_queue_selector.h"
-#include "components/scheduler/base/task_queue_sets.h"
 #include "components/scheduler/base/test_always_fail_time_source.h"
 #include "components/scheduler/base/test_time_source.h"
 #include "components/scheduler/base/virtual_time_domain.h"
+#include "components/scheduler/base/work_queue.h"
+#include "components/scheduler/base/work_queue_sets.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
 using testing::ElementsAre;
@@ -216,12 +217,12 @@
   Initialize(1u);
 
   std::vector<int> run_order;
-  EXPECT_FALSE(runners_[0]->HasPendingImmediateTask());
+  EXPECT_FALSE(runners_[0]->HasPendingImmediateWork());
   runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order));
-  EXPECT_TRUE(runners_[0]->HasPendingImmediateTask());
+  EXPECT_TRUE(runners_[0]->HasPendingImmediateWork());
 
   test_task_runner_->RunUntilIdle();
-  EXPECT_FALSE(runners_[0]->HasPendingImmediateTask());
+  EXPECT_FALSE(runners_[0]->HasPendingImmediateWork());
 }
 
 TEST_F(TaskQueueManagerTest, DelayedTaskPosting) {
@@ -232,8 +233,7 @@
   runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order),
                                delay);
   EXPECT_EQ(delay, test_task_runner_->DelayToNextTaskTime());
-  EXPECT_EQ(TaskQueue::QueueState::NO_IMMEDIATE_WORK,
-            runners_[0]->GetQueueState());
+  EXPECT_FALSE(runners_[0]->HasPendingImmediateWork());
   EXPECT_TRUE(run_order.empty());
 
   // The task doesn't run before the delay has completed.
@@ -243,7 +243,7 @@
   // After the delay has completed, the task runs normally.
   test_task_runner_->RunForPeriod(base::TimeDelta::FromMilliseconds(1));
   EXPECT_THAT(run_order, ElementsAre(1));
-  EXPECT_EQ(TaskQueue::QueueState::EMPTY, runners_[0]->GetQueueState());
+  EXPECT_FALSE(runners_[0]->HasPendingImmediateWork());
 }
 
 bool MessageLoopTaskCounter(size_t* count) {
@@ -377,10 +377,10 @@
   EXPECT_FALSE(test_task_runner_->HasPendingTasks());
 
   // However polling still works.
-  EXPECT_TRUE(runners_[0]->HasPendingImmediateTask());
+  EXPECT_TRUE(runners_[0]->HasPendingImmediateWork());
 
   // After pumping the task runs normally.
-  runners_[0]->PumpQueue();
+  runners_[0]->PumpQueue(true);
   EXPECT_TRUE(test_task_runner_->HasPendingTasks());
   test_task_runner_->RunUntilIdle();
   EXPECT_THAT(run_order, ElementsAre(1));
@@ -462,13 +462,13 @@
                                delay);
 
   // After pumping but before the delay period has expired, task does not run.
-  runners_[0]->PumpQueue();
+  runners_[0]->PumpQueue(true);
   test_task_runner_->RunForPeriod(base::TimeDelta::FromMilliseconds(5));
   EXPECT_TRUE(run_order.empty());
 
   // Once the delay has expired, pumping causes the task to run.
   now_src_->Advance(base::TimeDelta::FromMilliseconds(5));
-  runners_[0]->PumpQueue();
+  runners_[0]->PumpQueue(true);
   EXPECT_TRUE(test_task_runner_->HasPendingTasks());
   test_task_runner_->RunPendingTasks();
   EXPECT_THAT(run_order, ElementsAre(1));
@@ -496,7 +496,7 @@
   EXPECT_TRUE(run_order.empty());
 
   // Once the delay has expired, pumping causes the task to run.
-  runners_[0]->PumpQueue();
+  runners_[0]->PumpQueue(true);
   test_task_runner_->RunUntilIdle();
   EXPECT_THAT(run_order, ElementsAre(1, 2));
 }
@@ -522,11 +522,11 @@
   // Posting two tasks and pumping twice should result in two tasks in the work
   // queue.
   runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order));
-  runners_[0]->PumpQueue();
+  runners_[0]->PumpQueue(true);
   runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order));
-  runners_[0]->PumpQueue();
+  runners_[0]->PumpQueue(true);
 
-  EXPECT_EQ(2u, runners_[0]->WorkQueueSizeForTest());
+  EXPECT_EQ(2u, runners_[0]->immediate_work_queue()->Size());
 }
 
 void ReentrantTestTask(scoped_refptr<base::SingleThreadTaskRunner> runner,
@@ -596,7 +596,7 @@
       FROM_HERE, base::Bind(&RePostingTestTask, runners_[0], &run_count));
 
   test_task_runner_->RunPendingTasks();
-  // NOTE without the executing_task_ check in MaybePostDoWorkOnMainRunner there
+  // NOTE without the executing_task_ check in MaybeScheduleDoWork there
   // will be two tasks here.
   EXPECT_EQ(1u, test_task_runner_->NumPendingTasks());
   EXPECT_EQ(1, run_count);
@@ -691,7 +691,7 @@
   // This still shouldn't wake TQM as manual queue was not pumped.
   EXPECT_TRUE(run_order.empty());
 
-  runners_[1]->PumpQueue();
+  runners_[1]->PumpQueue(true);
   test_task_runner_->RunUntilIdle();
   // Executing a task on an auto pumped queue should wake the TQM.
   EXPECT_THAT(run_order, ElementsAre(2, 1));
@@ -1005,83 +1005,152 @@
   EXPECT_TRUE(manager_->GetAndClearSystemIsQuiescentBit());
 }
 
-TEST_F(TaskQueueManagerTest, HasPendingImmediateTask) {
+TEST_F(TaskQueueManagerTest, HasPendingImmediateWork) {
   Initialize(2u);
   internal::TaskQueueImpl* queue0 = runners_[0].get();
   internal::TaskQueueImpl* queue1 = runners_[1].get();
   queue0->SetPumpPolicy(TaskQueue::PumpPolicy::AUTO);
   queue1->SetPumpPolicy(TaskQueue::PumpPolicy::MANUAL);
 
-  EXPECT_FALSE(queue0->HasPendingImmediateTask());
-  EXPECT_FALSE(queue1->HasPendingImmediateTask());
+  EXPECT_FALSE(queue0->HasPendingImmediateWork());
+  EXPECT_FALSE(queue1->HasPendingImmediateWork());
 
   queue0->PostTask(FROM_HERE, base::Bind(NullTask));
   queue1->PostTask(FROM_HERE, base::Bind(NullTask));
-  EXPECT_TRUE(queue0->HasPendingImmediateTask());
-  EXPECT_TRUE(queue1->HasPendingImmediateTask());
+  EXPECT_TRUE(queue0->HasPendingImmediateWork());
+  EXPECT_TRUE(queue1->HasPendingImmediateWork());
 
   test_task_runner_->RunUntilIdle();
-  EXPECT_FALSE(queue0->HasPendingImmediateTask());
-  EXPECT_TRUE(queue1->HasPendingImmediateTask());
+  EXPECT_FALSE(queue0->HasPendingImmediateWork());
+  EXPECT_TRUE(queue1->HasPendingImmediateWork());
 
-  queue1->PumpQueue();
-  EXPECT_FALSE(queue0->HasPendingImmediateTask());
-  EXPECT_TRUE(queue1->HasPendingImmediateTask());
+  queue1->PumpQueue(true);
+  EXPECT_FALSE(queue0->HasPendingImmediateWork());
+  EXPECT_TRUE(queue1->HasPendingImmediateWork());
 
   test_task_runner_->RunUntilIdle();
-  EXPECT_FALSE(queue0->HasPendingImmediateTask());
-  EXPECT_FALSE(queue1->HasPendingImmediateTask());
+  EXPECT_FALSE(queue0->HasPendingImmediateWork());
+  EXPECT_FALSE(queue1->HasPendingImmediateWork());
 }
 
-TEST_F(TaskQueueManagerTest, GetQueueState) {
+TEST_F(TaskQueueManagerTest, HasPendingImmediateWorkAndNeedsPumping) {
   Initialize(2u);
   internal::TaskQueueImpl* queue0 = runners_[0].get();
   internal::TaskQueueImpl* queue1 = runners_[1].get();
   queue0->SetPumpPolicy(TaskQueue::PumpPolicy::AUTO);
   queue1->SetPumpPolicy(TaskQueue::PumpPolicy::MANUAL);
 
-  EXPECT_EQ(TaskQueue::QueueState::EMPTY, queue0->GetQueueState());
-  EXPECT_EQ(TaskQueue::QueueState::EMPTY, queue1->GetQueueState());
+  EXPECT_FALSE(queue0->HasPendingImmediateWork());
+  EXPECT_FALSE(queue0->NeedsPumping());
+  EXPECT_FALSE(queue1->HasPendingImmediateWork());
+  EXPECT_FALSE(queue1->NeedsPumping());
 
   queue0->PostTask(FROM_HERE, base::Bind(NullTask));
   queue0->PostTask(FROM_HERE, base::Bind(NullTask));
   queue1->PostTask(FROM_HERE, base::Bind(NullTask));
-  EXPECT_EQ(TaskQueue::QueueState::NEEDS_PUMPING, queue0->GetQueueState());
-  EXPECT_EQ(TaskQueue::QueueState::NEEDS_PUMPING, queue1->GetQueueState());
+  EXPECT_TRUE(queue0->HasPendingImmediateWork());
+  EXPECT_TRUE(queue0->NeedsPumping());
+  EXPECT_TRUE(queue1->HasPendingImmediateWork());
+  EXPECT_TRUE(queue1->NeedsPumping());
 
   test_task_runner_->SetRunTaskLimit(1);
   test_task_runner_->RunPendingTasks();
-  EXPECT_EQ(TaskQueue::QueueState::HAS_WORK, queue0->GetQueueState());
-  EXPECT_EQ(TaskQueue::QueueState::NEEDS_PUMPING, queue1->GetQueueState());
+  EXPECT_TRUE(queue0->HasPendingImmediateWork());
+  EXPECT_FALSE(queue0->NeedsPumping());
+  EXPECT_TRUE(queue1->HasPendingImmediateWork());
+  EXPECT_TRUE(queue1->NeedsPumping());
 
   test_task_runner_->ClearRunTaskLimit();
   test_task_runner_->RunUntilIdle();
-  EXPECT_EQ(TaskQueue::QueueState::EMPTY, queue0->GetQueueState());
-  EXPECT_EQ(TaskQueue::QueueState::NEEDS_PUMPING, queue1->GetQueueState());
+  EXPECT_FALSE(queue0->HasPendingImmediateWork());
+  EXPECT_FALSE(queue0->NeedsPumping());
+  EXPECT_TRUE(queue1->HasPendingImmediateWork());
+  EXPECT_TRUE(queue1->NeedsPumping());
 
-  queue1->PumpQueue();
-  EXPECT_EQ(TaskQueue::QueueState::EMPTY, queue0->GetQueueState());
-  EXPECT_EQ(TaskQueue::QueueState::HAS_WORK, queue1->GetQueueState());
+  queue1->PumpQueue(true);
+  EXPECT_FALSE(queue0->HasPendingImmediateWork());
+  EXPECT_FALSE(queue0->NeedsPumping());
+  EXPECT_TRUE(queue1->HasPendingImmediateWork());
+  EXPECT_FALSE(queue1->NeedsPumping());
 
   test_task_runner_->RunUntilIdle();
-  EXPECT_EQ(TaskQueue::QueueState::EMPTY, queue0->GetQueueState());
-  EXPECT_EQ(TaskQueue::QueueState::EMPTY, queue1->GetQueueState());
+  EXPECT_FALSE(queue0->HasPendingImmediateWork());
+  EXPECT_FALSE(queue0->NeedsPumping());
+  EXPECT_FALSE(queue1->HasPendingImmediateWork());
+  EXPECT_FALSE(queue1->NeedsPumping());
 }
 
-TEST_F(TaskQueueManagerTest, DelayedTaskDoesNotSkipAHeadOfNonDelayedTask) {
+void ExpensiveTestTask(int value,
+                       base::SimpleTestTickClock* clock,
+                       std::vector<int>* out_result) {
+  out_result->push_back(value);
+  clock->Advance(base::TimeDelta::FromMilliseconds(1));
+}
+
+TEST_F(TaskQueueManagerTest, ImmediateAndDelayedTaskRoundRobbin) {
+  Initialize(1u);
+
+  std::vector<int> run_order;
+  base::TimeDelta delay = base::TimeDelta::FromMilliseconds(10);
+  runners_[0]->PostDelayedTask(
+      FROM_HERE, base::Bind(&ExpensiveTestTask, 10, now_src_.get(), &run_order),
+      delay);
+  runners_[0]->PostDelayedTask(
+      FROM_HERE, base::Bind(&ExpensiveTestTask, 11, now_src_.get(), &run_order),
+      delay);
+  runners_[0]->PostDelayedTask(
+      FROM_HERE, base::Bind(&ExpensiveTestTask, 12, now_src_.get(), &run_order),
+      delay);
+  runners_[0]->PostDelayedTask(
+      FROM_HERE, base::Bind(&ExpensiveTestTask, 13, now_src_.get(), &run_order),
+      delay);
+
+  test_task_runner_->RunForPeriod(delay);
+
+  runners_[0]->PostTask(
+      FROM_HERE, base::Bind(&ExpensiveTestTask, 0, now_src_.get(), &run_order));
+  runners_[0]->PostTask(
+      FROM_HERE, base::Bind(&ExpensiveTestTask, 1, now_src_.get(), &run_order));
+  runners_[0]->PostTask(
+      FROM_HERE, base::Bind(&ExpensiveTestTask, 2, now_src_.get(), &run_order));
+  runners_[0]->PostTask(
+      FROM_HERE, base::Bind(&ExpensiveTestTask, 3, now_src_.get(), &run_order));
+
+  test_task_runner_->SetAutoAdvanceNowToPendingTasks(true);
+  test_task_runner_->RunUntilIdle();
+
+  EXPECT_THAT(run_order, ElementsAre(10, 0, 11, 1, 12, 2, 13, 3));
+}
+
+TEST_F(TaskQueueManagerTest,
+       DelayedTaskDoesNotSkipAHeadOfNonDelayedTask_SameQueue) {
+  Initialize(1u);
+
+  std::vector<int> run_order;
+  base::TimeDelta delay = base::TimeDelta::FromMilliseconds(10);
+  runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order));
+  runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 3, &run_order));
+  runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order),
+                               delay);
+
+  now_src_->Advance(delay * 2);
+  test_task_runner_->RunUntilIdle();
+
+  EXPECT_THAT(run_order, ElementsAre(2, 3, 1));
+}
+
+TEST_F(TaskQueueManagerTest,
+       DelayedTaskDoesNotSkipAHeadOfNonDelayedTask_DifferentQueues) {
   Initialize(2u);
 
   std::vector<int> run_order;
   base::TimeDelta delay = base::TimeDelta::FromMilliseconds(10);
-  runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order),
-                               delay);
   runners_[1]->PostTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order));
   runners_[1]->PostTask(FROM_HERE, base::Bind(&TestTask, 3, &run_order));
+  runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order),
+                               delay);
 
   now_src_->Advance(delay * 2);
-  // After task 2 has run, the automatic selector will have to choose between
-  // tasks 1 and 3.  The sequence numbers are used to choose between the two
-  // tasks and if they are correct task 1 will run last.
   test_task_runner_->RunUntilIdle();
 
   EXPECT_THAT(run_order, ElementsAre(2, 3, 1));
@@ -1171,7 +1240,7 @@
 
   // The sequence numbers are a zero-based monotonically incrememting counter
   // which should be set when the task is posted rather than when it's enqueued
-  // onto the incomming queue.
+  // onto the Incoming queue.
   EXPECT_THAT(observer.sequence_numbers(), ElementsAre(3, 2, 1, 0));
 
   manager_->RemoveTaskObserver(&observer);
@@ -1373,11 +1442,13 @@
                                base::TimeDelta::FromMilliseconds(30));
 
   domain_b->AdvanceTo(start_time + base::TimeDelta::FromMilliseconds(50));
+  manager_->MaybeScheduleImmediateWork(FROM_HERE);
 
   test_task_runner_->RunUntilIdle();
   EXPECT_THAT(run_order, ElementsAre(4, 5, 6));
 
   domain_a->AdvanceTo(start_time + base::TimeDelta::FromMilliseconds(50));
+  manager_->MaybeScheduleImmediateWork(FROM_HERE);
 
   test_task_runner_->RunUntilIdle();
   EXPECT_THAT(run_order, ElementsAre(4, 5, 6, 1, 2, 3));
@@ -1406,6 +1477,7 @@
                                base::TimeDelta::FromMilliseconds(40));
 
   domain_a->AdvanceTo(start_time + base::TimeDelta::FromMilliseconds(20));
+  manager_->MaybeScheduleImmediateWork(FROM_HERE);
   test_task_runner_->RunUntilIdle();
   EXPECT_THAT(run_order, ElementsAre(1, 2));
 
@@ -1415,6 +1487,7 @@
   runners_[0]->SetTimeDomain(domain_b.get());
 
   domain_b->AdvanceTo(start_time + base::TimeDelta::FromMilliseconds(50));
+  manager_->MaybeScheduleImmediateWork(FROM_HERE);
 
   test_task_runner_->RunUntilIdle();
   EXPECT_THAT(run_order, ElementsAre(1, 2, 3, 4));
@@ -1447,4 +1520,185 @@
   test_task_runner_->RunUntilIdle();
 }
 
+namespace {
+
+class QuadraticTask {
+ public:
+  QuadraticTask(scoped_refptr<internal::TaskQueueImpl> task_queue,
+                base::TimeDelta delay,
+                base::SimpleTestTickClock* now_src)
+      : count_(0), task_queue_(task_queue), delay_(delay), now_src_(now_src) {}
+
+  void SetShouldExit(base::Callback<bool()> should_exit) {
+    should_exit_ = should_exit;
+  }
+
+  void Run() {
+    if (should_exit_.Run())
+      return;
+    count_++;
+    task_queue_->PostDelayedTask(
+        FROM_HERE, base::Bind(&QuadraticTask::Run, base::Unretained(this)),
+        delay_);
+    task_queue_->PostDelayedTask(
+        FROM_HERE, base::Bind(&QuadraticTask::Run, base::Unretained(this)),
+        delay_);
+    now_src_->Advance(base::TimeDelta::FromMilliseconds(5));
+  }
+
+  int count() const { return count_; }
+
+ private:
+  int count_;
+  scoped_refptr<internal::TaskQueueImpl> task_queue_;
+  base::TimeDelta delay_;
+  base::Callback<bool()> should_exit_;
+  base::SimpleTestTickClock* now_src_;
+};
+
+class LinearTask {
+ public:
+  LinearTask(scoped_refptr<internal::TaskQueueImpl> task_queue,
+             base::TimeDelta delay,
+             base::SimpleTestTickClock* now_src)
+      : count_(0), task_queue_(task_queue), delay_(delay), now_src_(now_src) {}
+
+  void SetShouldExit(base::Callback<bool()> should_exit) {
+    should_exit_ = should_exit;
+  }
+
+  void Run() {
+    if (should_exit_.Run())
+      return;
+    count_++;
+    task_queue_->PostDelayedTask(
+        FROM_HERE, base::Bind(&LinearTask::Run, base::Unretained(this)),
+        delay_);
+    now_src_->Advance(base::TimeDelta::FromMilliseconds(5));
+  }
+
+  int count() const { return count_; }
+
+ private:
+  int count_;
+  scoped_refptr<internal::TaskQueueImpl> task_queue_;
+  base::TimeDelta delay_;
+  base::Callback<bool()> should_exit_;
+  base::SimpleTestTickClock* now_src_;
+};
+
+bool ShouldExit(QuadraticTask* quadratic_task, LinearTask* linear_task) {
+  return quadratic_task->count() == 1000 || linear_task->count() == 1000;
+}
+
+}  // namespace
+
+TEST_F(TaskQueueManagerTest, DelayedTasksDontStarveNonDelayedWork_SameQueue) {
+  Initialize(1u);
+
+  QuadraticTask quadratic_delayed_task(
+      runners_[0], base::TimeDelta::FromMilliseconds(10), now_src_.get());
+  LinearTask linear_immediate_task(runners_[0], base::TimeDelta(),
+                                   now_src_.get());
+  base::Callback<bool()> should_exit =
+      base::Bind(ShouldExit, &quadratic_delayed_task, &linear_immediate_task);
+  quadratic_delayed_task.SetShouldExit(should_exit);
+  linear_immediate_task.SetShouldExit(should_exit);
+
+  quadratic_delayed_task.Run();
+  linear_immediate_task.Run();
+
+  test_task_runner_->SetAutoAdvanceNowToPendingTasks(true);
+  test_task_runner_->RunUntilIdle();
+
+  double ratio = static_cast<double>(linear_immediate_task.count()) /
+                 static_cast<double>(quadratic_delayed_task.count());
+
+  EXPECT_GT(ratio, 0.9);
+  EXPECT_LT(ratio, 1.1);
+}
+
+TEST_F(TaskQueueManagerTest, ImmediateWorkCanStarveDelayedTasks_SameQueue) {
+  Initialize(1u);
+
+  QuadraticTask quadratic_immediate_task(runners_[0], base::TimeDelta(),
+                                         now_src_.get());
+  LinearTask linear_delayed_task(
+      runners_[0], base::TimeDelta::FromMilliseconds(10), now_src_.get());
+  base::Callback<bool()> should_exit =
+      base::Bind(&ShouldExit, &quadratic_immediate_task, &linear_delayed_task);
+
+  quadratic_immediate_task.SetShouldExit(should_exit);
+  linear_delayed_task.SetShouldExit(should_exit);
+
+  quadratic_immediate_task.Run();
+  linear_delayed_task.Run();
+
+  test_task_runner_->SetAutoAdvanceNowToPendingTasks(true);
+  test_task_runner_->RunUntilIdle();
+
+  double ratio = static_cast<double>(linear_delayed_task.count()) /
+                 static_cast<double>(quadratic_immediate_task.count());
+
+  // This is by design, we want to enforce a strict ordering in task execution
+  // where by delayed tasks can not skip ahead of non-delayed work.
+  EXPECT_GT(ratio, 0.0);
+  EXPECT_LT(ratio, 0.1);
+}
+
+TEST_F(TaskQueueManagerTest,
+       DelayedTasksDontStarveNonDelayedWork_DifferentQueue) {
+  Initialize(2u);
+
+  QuadraticTask quadratic_delayed_task(
+      runners_[0], base::TimeDelta::FromMilliseconds(10), now_src_.get());
+  LinearTask linear_immediate_task(runners_[1], base::TimeDelta(),
+                                   now_src_.get());
+  base::Callback<bool()> should_exit =
+      base::Bind(ShouldExit, &quadratic_delayed_task, &linear_immediate_task);
+  quadratic_delayed_task.SetShouldExit(should_exit);
+  linear_immediate_task.SetShouldExit(should_exit);
+
+  quadratic_delayed_task.Run();
+  linear_immediate_task.Run();
+
+  test_task_runner_->SetAutoAdvanceNowToPendingTasks(true);
+  test_task_runner_->RunUntilIdle();
+
+  double ratio = static_cast<double>(linear_immediate_task.count()) /
+                 static_cast<double>(quadratic_delayed_task.count());
+
+  EXPECT_GT(ratio, 0.9);
+  EXPECT_LT(ratio, 1.1);
+}
+
+TEST_F(TaskQueueManagerTest,
+       ImmediateWorkCanStarveDelayedTasks_DifferentQueue) {
+  Initialize(2u);
+
+  QuadraticTask quadratic_immediate_task(runners_[0], base::TimeDelta(),
+                                         now_src_.get());
+  LinearTask linear_delayed_task(
+      runners_[1], base::TimeDelta::FromMilliseconds(10), now_src_.get());
+  base::Callback<bool()> should_exit =
+      base::Bind(&ShouldExit, &quadratic_immediate_task, &linear_delayed_task);
+
+  quadratic_immediate_task.SetShouldExit(should_exit);
+  linear_delayed_task.SetShouldExit(should_exit);
+
+  quadratic_immediate_task.Run();
+  linear_delayed_task.Run();
+
+  test_task_runner_->SetAutoAdvanceNowToPendingTasks(true);
+  test_task_runner_->RunUntilIdle();
+
+  double ratio = static_cast<double>(linear_delayed_task.count()) /
+                 static_cast<double>(quadratic_immediate_task.count());
+
+  // This is by design, we want to enforce a strict ordering in task execution
+  // where by delayed tasks can not skip ahead of non-delayed work.
+  EXPECT_GT(ratio, 0.0);
+  EXPECT_LT(ratio, 0.1);
+}
+
 }  // namespace scheduler
diff --git a/components/scheduler/base/task_queue_selector.cc b/components/scheduler/base/task_queue_selector.cc
index 0b65ec3d..c72c33a 100644
--- a/components/scheduler/base/task_queue_selector.cc
+++ b/components/scheduler/base/task_queue_selector.cc
@@ -7,12 +7,15 @@
 #include "base/logging.h"
 #include "base/trace_event/trace_event_argument.h"
 #include "components/scheduler/base/task_queue_impl.h"
+#include "components/scheduler/base/work_queue.h"
 
 namespace scheduler {
 namespace internal {
 
 TaskQueueSelector::TaskQueueSelector()
-    : task_queue_sets_(TaskQueue::QUEUE_PRIORITY_COUNT),
+    : delayed_work_queue_sets_(TaskQueue::QUEUE_PRIORITY_COUNT),
+      immediate_work_queue_sets_(TaskQueue::QUEUE_PRIORITY_COUNT),
+      force_select_immediate_(true),
       starvation_count_(0),
       task_queue_selector_observer_(nullptr) {}
 
@@ -20,21 +23,29 @@
 
 void TaskQueueSelector::AddQueue(internal::TaskQueueImpl* queue) {
   DCHECK(main_thread_checker_.CalledOnValidThread());
-  task_queue_sets_.AssignQueueToSet(queue, TaskQueue::NORMAL_PRIORITY);
+  delayed_work_queue_sets_.AssignQueueToSet(queue->delayed_work_queue(),
+                                            TaskQueue::NORMAL_PRIORITY);
+  immediate_work_queue_sets_.AssignQueueToSet(queue->immediate_work_queue(),
+                                              TaskQueue::NORMAL_PRIORITY);
 }
 
 void TaskQueueSelector::RemoveQueue(internal::TaskQueueImpl* queue) {
   DCHECK(main_thread_checker_.CalledOnValidThread());
-  task_queue_sets_.RemoveQueue(queue);
+  delayed_work_queue_sets_.RemoveQueue(queue->delayed_work_queue());
+  immediate_work_queue_sets_.RemoveQueue(queue->immediate_work_queue());
 }
 
 void TaskQueueSelector::SetQueuePriority(internal::TaskQueueImpl* queue,
                                          TaskQueue::QueuePriority priority) {
   DCHECK(main_thread_checker_.CalledOnValidThread());
   DCHECK_LT(priority, TaskQueue::QUEUE_PRIORITY_COUNT);
+  int old_set_index = queue->immediate_work_queue()->work_queue_set_index();
   TaskQueue::QueuePriority old_priority =
-      static_cast<TaskQueue::QueuePriority>(queue->get_task_queue_set_index());
-  task_queue_sets_.AssignQueueToSet(queue, priority);
+      static_cast<TaskQueue::QueuePriority>(old_set_index);
+  delayed_work_queue_sets_.AssignQueueToSet(queue->delayed_work_queue(),
+                                            priority);
+  immediate_work_queue_sets_.AssignQueueToSet(queue->immediate_work_queue(),
+                                              priority);
   if (task_queue_selector_observer_ &&
       old_priority == TaskQueue::DISABLED_PRIORITY) {
     task_queue_selector_observer_->OnTaskQueueEnabled(queue);
@@ -44,8 +55,9 @@
 bool TaskQueueSelector::IsQueueEnabled(
     const internal::TaskQueueImpl* queue) const {
   DCHECK(main_thread_checker_.CalledOnValidThread());
-  return static_cast<TaskQueue::QueuePriority>(
-             queue->get_task_queue_set_index()) != TaskQueue::DISABLED_PRIORITY;
+  size_t set_index = queue->delayed_work_queue()->work_queue_set_index();
+  return static_cast<TaskQueue::QueuePriority>(set_index) !=
+         TaskQueue::DISABLED_PRIORITY;
 }
 
 TaskQueue::QueuePriority TaskQueueSelector::NextPriority(
@@ -54,23 +66,83 @@
   return static_cast<TaskQueue::QueuePriority>(static_cast<int>(priority) + 1);
 }
 
-bool TaskQueueSelector::ChooseOldestWithPriority(
+bool TaskQueueSelector::ChooseOldestImmediateTaskWithPriority(
     TaskQueue::QueuePriority priority,
-    internal::TaskQueueImpl** out_queue) const {
-  return task_queue_sets_.GetOldestQueueInSet(priority, out_queue);
+    WorkQueue** out_work_queue) const {
+  return immediate_work_queue_sets_.GetOldestQueueInSet(priority,
+                                                        out_work_queue);
 }
 
-bool TaskQueueSelector::SelectQueueToService(
-    internal::TaskQueueImpl** out_queue) {
+bool TaskQueueSelector::ChooseOldestDelayedTaskWithPriority(
+    TaskQueue::QueuePriority priority,
+    WorkQueue** out_work_queue) const {
+  return delayed_work_queue_sets_.GetOldestQueueInSet(priority, out_work_queue);
+}
+
+bool TaskQueueSelector::ChooseOldestImmediateOrDelayedTaskWithPriority(
+    TaskQueue::QueuePriority priority,
+    WorkQueue** out_work_queue) const {
+  WorkQueue* immediate_queue;
+  if (immediate_work_queue_sets_.GetOldestQueueInSet(priority,
+                                                     &immediate_queue)) {
+    WorkQueue* delayed_queue;
+    if (delayed_work_queue_sets_.GetOldestQueueInSet(priority,
+                                                     &delayed_queue)) {
+      int immediate_enqueue_order;
+      int delayed_enqueue_order;
+      bool have_immediate_task =
+          immediate_queue->GetFrontTaskEnqueueOrder(&immediate_enqueue_order);
+      bool have_delayed_task =
+          delayed_queue->GetFrontTaskEnqueueOrder(&delayed_enqueue_order);
+      DCHECK(have_immediate_task);
+      DCHECK(have_delayed_task);
+      if (immediate_enqueue_order < delayed_enqueue_order) {
+        *out_work_queue = immediate_queue;
+      } else {
+        *out_work_queue = delayed_queue;
+      }
+    } else {
+      *out_work_queue = immediate_queue;
+    }
+    return true;
+  } else {
+    if (delayed_work_queue_sets_.GetOldestQueueInSet(priority,
+                                                     out_work_queue)) {
+      return true;
+    } else {
+      return false;
+    }
+  }
+}
+
+bool TaskQueueSelector::ChooseOldestWithPriority(
+    TaskQueue::QueuePriority priority,
+    WorkQueue** out_work_queue) const {
+  if (force_select_immediate_) {
+    if (ChooseOldestImmediateTaskWithPriority(priority, out_work_queue)) {
+      return true;
+    }
+    if (ChooseOldestDelayedTaskWithPriority(priority, out_work_queue)) {
+      return true;
+    }
+    return false;
+  } else {
+    return ChooseOldestImmediateOrDelayedTaskWithPriority(priority,
+                                                          out_work_queue);
+  }
+}
+
+bool TaskQueueSelector::SelectWorkQueueToService(WorkQueue** out_work_queue) {
   DCHECK(main_thread_checker_.CalledOnValidThread());
+  force_select_immediate_ = !force_select_immediate_;
   // Always service the control queue if it has any work.
-  if (ChooseOldestWithPriority(TaskQueue::CONTROL_PRIORITY, out_queue)) {
+  if (ChooseOldestWithPriority(TaskQueue::CONTROL_PRIORITY, out_work_queue)) {
     DidSelectQueueWithPriority(TaskQueue::CONTROL_PRIORITY);
     return true;
   }
   // Select from the normal priority queue if we are starving it.
   if (starvation_count_ >= kMaxStarvationTasks &&
-      ChooseOldestWithPriority(TaskQueue::NORMAL_PRIORITY, out_queue)) {
+      ChooseOldestWithPriority(TaskQueue::NORMAL_PRIORITY, out_work_queue)) {
     DidSelectQueueWithPriority(TaskQueue::NORMAL_PRIORITY);
     return true;
   }
@@ -78,7 +150,7 @@
   for (TaskQueue::QueuePriority priority = TaskQueue::HIGH_PRIORITY;
        priority < TaskQueue::DISABLED_PRIORITY;
        priority = NextPriority(priority)) {
-    if (ChooseOldestWithPriority(priority, out_queue)) {
+    if (ChooseOldestWithPriority(priority, out_work_queue)) {
       DidSelectQueueWithPriority(priority);
       return true;
     }
@@ -107,6 +179,7 @@
     base::trace_event::TracedValue* state) const {
   DCHECK(main_thread_checker_.CalledOnValidThread());
   state->SetInteger("starvation_count", starvation_count_);
+  state->SetBoolean("try_delayed_first", force_select_immediate_);
 }
 
 void TaskQueueSelector::SetTaskQueueSelectorObserver(Observer* observer) {
@@ -117,11 +190,18 @@
   for (TaskQueue::QueuePriority priority = TaskQueue::HIGH_PRIORITY;
        priority < TaskQueue::DISABLED_PRIORITY;
        priority = NextPriority(priority)) {
-    if (!task_queue_sets_.IsSetEmpty(priority))
+    if (!delayed_work_queue_sets_.IsSetEmpty(priority) ||
+        !immediate_work_queue_sets_.IsSetEmpty(priority)) {
       return false;
+    }
   }
   return true;
 }
 
+void TaskQueueSelector::SetForceSelectImmediateForTest(
+    bool force_select_immediate) {
+  force_select_immediate_ = force_select_immediate;
+}
+
 }  // namespace internal
 }  // namespace scheduler
diff --git a/components/scheduler/base/task_queue_selector.h b/components/scheduler/base/task_queue_selector.h
index 59e1349..2093528 100644
--- a/components/scheduler/base/task_queue_selector.h
+++ b/components/scheduler/base/task_queue_selector.h
@@ -10,7 +10,7 @@
 #include "base/compiler_specific.h"
 #include "base/pending_task.h"
 #include "base/threading/thread_checker.h"
-#include "components/scheduler/base/task_queue_sets.h"
+#include "components/scheduler/base/work_queue_sets.h"
 #include "components/scheduler/scheduler_export.h"
 
 namespace scheduler {
@@ -39,11 +39,11 @@
   void RemoveQueue(internal::TaskQueueImpl* queue);
 
   // Called to choose the work queue from which the next task should be taken
-  // and run. Return true if |out_queue| indicates the queue to service or
+  // and run. Return true if |out_work_queue| indicates the queue to service or
   // false to avoid running any task.
   //
   // This function is called on the main thread.
-  bool SelectQueueToService(internal::TaskQueueImpl** out_queue);
+  bool SelectWorkQueueToService(WorkQueue** out_work_queue);
 
   // Serialize the selector state for tracing.
   void AsValueInto(base::trace_event::TracedValue* state) const;
@@ -60,22 +60,38 @@
   // on the main thread. If |observer| is null, then no callbacks will occur.
   void SetTaskQueueSelectorObserver(Observer* observer);
 
-  TaskQueueSets* GetTaskQueueSets() { return &task_queue_sets_; }
+  WorkQueueSets* delayed_task_queue_sets() { return &delayed_work_queue_sets_; }
+  WorkQueueSets* immediate_task_queue_sets() {
+    return &immediate_work_queue_sets_;
+  }
 
   // Returns true if all the enabled work queues are empty. Returns false
   // otherwise.
   bool EnabledWorkQueuesEmpty() const;
 
+ protected:
+  // Return true if |out_queue| contains the queue with the oldest pending task
+  // from the set of queues of |priority|, or false if all queues of that
+  // priority are empty.
+  bool ChooseOldestWithPriority(TaskQueue::QueuePriority priority,
+                                WorkQueue** out_work_queue) const;
+
+  void SetForceSelectImmediateForTest(bool force_select_immediate);
+
  private:
   // Returns the priority which is next after |priority|.
   static TaskQueue::QueuePriority NextPriority(
       TaskQueue::QueuePriority priority);
 
-  // Return true if |out_queue| contains the queue with the oldest pending task
-  // from the set of queues of |priority|, or false if all queues of that
-  // priority are empty.
-  bool ChooseOldestWithPriority(TaskQueue::QueuePriority priority,
-                                internal::TaskQueueImpl** out_queue) const;
+  bool ChooseOldestImmediateTaskWithPriority(TaskQueue::QueuePriority priority,
+                                             WorkQueue** out_work_queue) const;
+
+  bool ChooseOldestDelayedTaskWithPriority(TaskQueue::QueuePriority priority,
+                                           WorkQueue** out_work_queue) const;
+
+  bool ChooseOldestImmediateOrDelayedTaskWithPriority(
+      TaskQueue::QueuePriority priority,
+      WorkQueue** out_work_queue) const;
 
   // Called whenever the selector chooses a task queue for execution with the
   // priority |priority|.
@@ -86,8 +102,11 @@
   // TODO(rmcilroy): Check if this is a good value.
   static const size_t kMaxStarvationTasks = 5;
 
+ private:
   base::ThreadChecker main_thread_checker_;
-  TaskQueueSets task_queue_sets_;
+  WorkQueueSets delayed_work_queue_sets_;
+  WorkQueueSets immediate_work_queue_sets_;
+  bool force_select_immediate_;
 
   size_t starvation_count_;
   Observer* task_queue_selector_observer_;  // NOT OWNED
diff --git a/components/scheduler/base/task_queue_selector_unittest.cc b/components/scheduler/base/task_queue_selector_unittest.cc
index da64fac..6eb4457 100644
--- a/components/scheduler/base/task_queue_selector_unittest.cc
+++ b/components/scheduler/base/task_queue_selector_unittest.cc
@@ -8,8 +8,9 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/pending_task.h"
 #include "components/scheduler/base/task_queue_impl.h"
-#include "components/scheduler/base/task_queue_sets.h"
 #include "components/scheduler/base/virtual_time_domain.h"
+#include "components/scheduler/base/work_queue.h"
+#include "components/scheduler/base/work_queue_sets.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -29,44 +30,57 @@
   DISALLOW_COPY_AND_ASSIGN(MockObserver);
 };
 
+class TaskQueueSelectorForTest : public TaskQueueSelector {
+ public:
+  using TaskQueueSelector::ChooseOldestWithPriority;
+  using TaskQueueSelector::SetForceSelectImmediateForTest;
+};
+
 class TaskQueueSelectorTest : public testing::Test {
  public:
   TaskQueueSelectorTest()
       : test_closure_(base::Bind(&TaskQueueSelectorTest::TestFunction)) {}
   ~TaskQueueSelectorTest() override {}
 
-  std::vector<TaskQueueImpl::Task> GetTasks(int count) {
-    std::vector<TaskQueueImpl::Task> tasks;
-    for (int i = 0; i < count; i++) {
-      TaskQueueImpl::Task task(FROM_HERE, test_closure_, 0, true);
-      task.set_enqueue_order(i);
-      tasks.push_back(task);
-    }
-    return tasks;
-  }
-
-  void PushTasks(const std::vector<TaskQueueImpl::Task>& tasks,
-                 const size_t queue_indices[]) {
+  void PushTasks(const size_t queue_indices[], size_t num_tasks) {
     std::set<size_t> changed_queue_set;
-    for (size_t i = 0; i < tasks.size(); i++) {
+    for (size_t i = 0; i < num_tasks; i++) {
       changed_queue_set.insert(queue_indices[i]);
-      task_queues_[queue_indices[i]]->PushTaskOntoWorkQueueForTest(tasks[i]);
+      task_queues_[queue_indices[i]]->immediate_work_queue()->PushTaskForTest(
+          TaskQueueImpl::Task(FROM_HERE, test_closure_, base::TimeTicks(), 0,
+                              true, i));
     }
     for (size_t queue_index : changed_queue_set) {
-      selector_.GetTaskQueueSets()->OnPushQueue(
-          task_queues_[queue_index].get());
+      selector_.immediate_task_queue_sets()->OnPushQueue(
+          task_queues_[queue_index]->immediate_work_queue());
+    }
+  }
+
+  void PushTasksWithEnqueueOrder(const size_t queue_indices[],
+                                 const size_t enqueue_orders[],
+                                 size_t num_tasks) {
+    std::set<size_t> changed_queue_set;
+    for (size_t i = 0; i < num_tasks; i++) {
+      changed_queue_set.insert(queue_indices[i]);
+      task_queues_[queue_indices[i]]->immediate_work_queue()->PushTaskForTest(
+          TaskQueueImpl::Task(FROM_HERE, test_closure_, base::TimeTicks(), 0,
+                              true, enqueue_orders[i]));
+    }
+    for (size_t queue_index : changed_queue_set) {
+      selector_.immediate_task_queue_sets()->OnPushQueue(
+          task_queues_[queue_index]->immediate_work_queue());
     }
   }
 
   std::vector<size_t> PopTasks() {
     std::vector<size_t> order;
-    TaskQueueImpl* chosen_queue;
-    while (selector_.SelectQueueToService(&chosen_queue)) {
+    WorkQueue* chosen_work_queue;
+    while (selector_.SelectWorkQueueToService(&chosen_work_queue)) {
       size_t chosen_queue_index =
-          queue_to_index_map_.find(chosen_queue)->second;
+          queue_to_index_map_.find(chosen_work_queue->task_queue())->second;
       order.push_back(chosen_queue_index);
-      chosen_queue->PopTaskFromWorkQueueForTest();
-      selector_.GetTaskQueueSets()->OnPopQueue(chosen_queue);
+      chosen_work_queue->PopTaskForTest();
+      selector_.immediate_task_queue_sets()->OnPopQueue(chosen_work_queue);
     }
     return order;
   }
@@ -92,31 +106,28 @@
 
   const size_t kTaskQueueCount = 5;
   base::Closure test_closure_;
-  TaskQueueSelector selector_;
+  TaskQueueSelectorForTest selector_;
   scoped_ptr<VirtualTimeDomain> virtual_time_domain_;
   std::vector<scoped_refptr<TaskQueueImpl>> task_queues_;
   std::map<TaskQueueImpl*, size_t> queue_to_index_map_;
 };
 
 TEST_F(TaskQueueSelectorTest, TestDefaultPriority) {
-  std::vector<TaskQueueImpl::Task> tasks = GetTasks(5);
   size_t queue_order[] = {4, 3, 2, 1, 0};
-  PushTasks(tasks, queue_order);
+  PushTasks(queue_order, 5);
   EXPECT_THAT(PopTasks(), testing::ElementsAre(4, 3, 2, 1, 0));
 }
 
 TEST_F(TaskQueueSelectorTest, TestHighPriority) {
-  std::vector<TaskQueueImpl::Task> tasks = GetTasks(5);
   size_t queue_order[] = {0, 1, 2, 3, 4};
-  PushTasks(tasks, queue_order);
+  PushTasks(queue_order, 5);
   selector_.SetQueuePriority(task_queues_[2].get(), TaskQueue::HIGH_PRIORITY);
   EXPECT_THAT(PopTasks(), testing::ElementsAre(2, 0, 1, 3, 4));
 }
 
 TEST_F(TaskQueueSelectorTest, TestBestEffortPriority) {
-  std::vector<TaskQueueImpl::Task> tasks = GetTasks(5);
   size_t queue_order[] = {0, 1, 2, 3, 4};
-  PushTasks(tasks, queue_order);
+  PushTasks(queue_order, 5);
   selector_.SetQueuePriority(task_queues_[0].get(),
                              TaskQueue::BEST_EFFORT_PRIORITY);
   selector_.SetQueuePriority(task_queues_[2].get(), TaskQueue::HIGH_PRIORITY);
@@ -124,9 +135,8 @@
 }
 
 TEST_F(TaskQueueSelectorTest, TestControlPriority) {
-  std::vector<TaskQueueImpl::Task> tasks = GetTasks(5);
   size_t queue_order[] = {0, 1, 2, 3, 4};
-  PushTasks(tasks, queue_order);
+  PushTasks(queue_order, 5);
   selector_.SetQueuePriority(task_queues_[4].get(),
                              TaskQueue::CONTROL_PRIORITY);
   EXPECT_TRUE(selector_.IsQueueEnabled(task_queues_[4].get()));
@@ -157,9 +167,8 @@
   MockObserver mock_observer;
   selector_.SetTaskQueueSelectorObserver(&mock_observer);
 
-  std::vector<TaskQueueImpl::Task> tasks = GetTasks(5);
   size_t queue_order[] = {0, 1, 2, 3, 4};
-  PushTasks(tasks, queue_order);
+  PushTasks(queue_order, 5);
   selector_.SetQueuePriority(task_queues_[2].get(),
                              TaskQueue::DISABLED_PRIORITY);
   EXPECT_FALSE(selector_.IsQueueEnabled(task_queues_[2].get()));
@@ -177,61 +186,53 @@
 }
 
 TEST_F(TaskQueueSelectorTest, TestEmptyQueues) {
-  TaskQueueImpl* chosen_queue = nullptr;
-  EXPECT_FALSE(selector_.SelectQueueToService(&chosen_queue));
+  WorkQueue* chosen_work_queue = nullptr;
+  EXPECT_FALSE(selector_.SelectWorkQueueToService(&chosen_work_queue));
 
   // Test only disabled queues.
-  std::vector<TaskQueueImpl::Task> tasks = GetTasks(1);
   size_t queue_order[] = {0};
-  PushTasks(tasks, queue_order);
+  PushTasks(queue_order, 1);
   selector_.SetQueuePriority(task_queues_[0].get(),
                              TaskQueue::DISABLED_PRIORITY);
   EXPECT_FALSE(selector_.IsQueueEnabled(task_queues_[0].get()));
-  EXPECT_FALSE(selector_.SelectQueueToService(&chosen_queue));
+  EXPECT_FALSE(selector_.SelectWorkQueueToService(&chosen_work_queue));
 }
 
 TEST_F(TaskQueueSelectorTest, TestAge) {
-  std::vector<TaskQueueImpl::Task> tasks;
-  int enqueue_order[] = {10, 1, 2, 9, 4};
-  for (int i = 0; i < 5; i++) {
-    TaskQueueImpl::Task task(FROM_HERE, test_closure_, 0, true);
-    task.set_enqueue_order(enqueue_order[i]);
-    tasks.push_back(task);
-  }
+  size_t enqueue_order[] = {10, 1, 2, 9, 4};
   size_t queue_order[] = {0, 1, 2, 3, 4};
-  PushTasks(tasks, queue_order);
+  PushTasksWithEnqueueOrder(queue_order, enqueue_order, 5);
   EXPECT_THAT(PopTasks(), testing::ElementsAre(1, 2, 4, 3, 0));
 }
 
 TEST_F(TaskQueueSelectorTest, TestControlStarvesOthers) {
-  std::vector<TaskQueueImpl::Task> tasks = GetTasks(4);
   size_t queue_order[] = {0, 1, 2, 3};
-  PushTasks(tasks, queue_order);
+  PushTasks(queue_order, 4);
   selector_.SetQueuePriority(task_queues_[3].get(),
                              TaskQueue::CONTROL_PRIORITY);
   selector_.SetQueuePriority(task_queues_[2].get(), TaskQueue::HIGH_PRIORITY);
   selector_.SetQueuePriority(task_queues_[1].get(),
                              TaskQueue::BEST_EFFORT_PRIORITY);
   for (int i = 0; i < 100; i++) {
-    TaskQueueImpl* chosen_queue = nullptr;
-    EXPECT_TRUE(selector_.SelectQueueToService(&chosen_queue));
-    EXPECT_EQ(task_queues_[3].get(), chosen_queue);
+    WorkQueue* chosen_work_queue = nullptr;
+    EXPECT_TRUE(selector_.SelectWorkQueueToService(&chosen_work_queue));
+    EXPECT_EQ(task_queues_[3].get(), chosen_work_queue->task_queue());
     // Don't remove task from queue to simulate all queues still being full.
   }
 }
 
 TEST_F(TaskQueueSelectorTest, TestHighPriorityDoesNotStarveNormal) {
-  std::vector<TaskQueueImpl::Task> tasks = GetTasks(3);
   size_t queue_order[] = {0, 1, 2};
-  PushTasks(tasks, queue_order);
+  PushTasks(queue_order, 3);
   selector_.SetQueuePriority(task_queues_[2].get(), TaskQueue::HIGH_PRIORITY);
   selector_.SetQueuePriority(task_queues_[1].get(),
                              TaskQueue::BEST_EFFORT_PRIORITY);
   size_t counts[] = {0, 0, 0};
   for (int i = 0; i < 100; i++) {
-    TaskQueueImpl* chosen_queue = nullptr;
-    EXPECT_TRUE(selector_.SelectQueueToService(&chosen_queue));
-    size_t chosen_queue_index = queue_to_index_map_.find(chosen_queue)->second;
+    WorkQueue* chosen_work_queue = nullptr;
+    EXPECT_TRUE(selector_.SelectWorkQueueToService(&chosen_work_queue));
+    size_t chosen_queue_index =
+        queue_to_index_map_.find(chosen_work_queue->task_queue())->second;
     counts[chosen_queue_index]++;
     // Don't remove task from queue to simulate all queues still being full.
   }
@@ -241,29 +242,28 @@
 }
 
 TEST_F(TaskQueueSelectorTest, TestBestEffortGetsStarved) {
-  std::vector<TaskQueueImpl::Task> tasks = GetTasks(2);
   size_t queue_order[] = {0, 1};
-  PushTasks(tasks, queue_order);
+  PushTasks(queue_order, 2);
   selector_.SetQueuePriority(task_queues_[0].get(),
                              TaskQueue::BEST_EFFORT_PRIORITY);
   selector_.SetQueuePriority(task_queues_[1].get(), TaskQueue::NORMAL_PRIORITY);
-  TaskQueueImpl* chosen_queue = nullptr;
+  WorkQueue* chosen_work_queue = nullptr;
   for (int i = 0; i < 100; i++) {
-    EXPECT_TRUE(selector_.SelectQueueToService(&chosen_queue));
-    EXPECT_EQ(task_queues_[1].get(), chosen_queue);
+    EXPECT_TRUE(selector_.SelectWorkQueueToService(&chosen_work_queue));
+    EXPECT_EQ(task_queues_[1].get(), chosen_work_queue->task_queue());
     // Don't remove task from queue to simulate all queues still being full.
   }
   selector_.SetQueuePriority(task_queues_[1].get(), TaskQueue::HIGH_PRIORITY);
   for (int i = 0; i < 100; i++) {
-    EXPECT_TRUE(selector_.SelectQueueToService(&chosen_queue));
-    EXPECT_EQ(task_queues_[1].get(), chosen_queue);
+    EXPECT_TRUE(selector_.SelectWorkQueueToService(&chosen_work_queue));
+    EXPECT_EQ(task_queues_[1].get(), chosen_work_queue->task_queue());
     // Don't remove task from queue to simulate all queues still being full.
   }
   selector_.SetQueuePriority(task_queues_[1].get(),
                              TaskQueue::CONTROL_PRIORITY);
   for (int i = 0; i < 100; i++) {
-    EXPECT_TRUE(selector_.SelectQueueToService(&chosen_queue));
-    EXPECT_EQ(task_queues_[1].get(), chosen_queue);
+    EXPECT_TRUE(selector_.SelectWorkQueueToService(&chosen_work_queue));
+    EXPECT_EQ(task_queues_[1].get(), chosen_work_queue->task_queue());
     // Don't remove task from queue to simulate all queues still being full.
   }
 }
@@ -274,14 +274,90 @@
 
 TEST_F(TaskQueueSelectorTest, EnabledWorkQueuesEmpty) {
   EXPECT_TRUE(selector_.EnabledWorkQueuesEmpty());
-  std::vector<TaskQueueImpl::Task> tasks = GetTasks(2);
   size_t queue_order[] = {0, 1};
-  PushTasks(tasks, queue_order);
+  PushTasks(queue_order, 2);
 
   EXPECT_FALSE(selector_.EnabledWorkQueuesEmpty());
   PopTasks();
   EXPECT_TRUE(selector_.EnabledWorkQueuesEmpty());
 }
 
+TEST_F(TaskQueueSelectorTest, ChooseOldestWithPriority_Empty) {
+  WorkQueue* chosen_work_queue = nullptr;
+  EXPECT_FALSE(selector_.ChooseOldestWithPriority(TaskQueue::NORMAL_PRIORITY,
+                                                  &chosen_work_queue));
+}
+
+TEST_F(TaskQueueSelectorTest, ChooseOldestWithPriority_OnlyDelayed) {
+  task_queues_[0]->delayed_work_queue()->PushTaskForTest(TaskQueueImpl::Task(
+      FROM_HERE, test_closure_, base::TimeTicks(), 0, true, 0));
+  selector_.delayed_task_queue_sets()->OnPushQueue(
+      task_queues_[0]->delayed_work_queue());
+
+  WorkQueue* chosen_work_queue = nullptr;
+  EXPECT_TRUE(selector_.ChooseOldestWithPriority(TaskQueue::NORMAL_PRIORITY,
+                                                 &chosen_work_queue));
+  EXPECT_EQ(chosen_work_queue, task_queues_[0]->delayed_work_queue());
+}
+
+TEST_F(TaskQueueSelectorTest, ChooseOldestWithPriority_OnlyImmediate) {
+  task_queues_[0]->immediate_work_queue()->PushTaskForTest(TaskQueueImpl::Task(
+      FROM_HERE, test_closure_, base::TimeTicks(), 0, true, 0));
+  selector_.immediate_task_queue_sets()->OnPushQueue(
+      task_queues_[0]->immediate_work_queue());
+
+  WorkQueue* chosen_work_queue = nullptr;
+  EXPECT_TRUE(selector_.ChooseOldestWithPriority(TaskQueue::NORMAL_PRIORITY,
+                                                 &chosen_work_queue));
+  EXPECT_EQ(chosen_work_queue, task_queues_[0]->immediate_work_queue());
+}
+
+struct ChooseOldestWithPriorityTestParam {
+  int delayed_task_enqueue_order;
+  int immediate_task_enqueue_order;
+  bool force_select_immediate;
+  const char* expected_work_queue_name;
+};
+
+static const ChooseOldestWithPriorityTestParam
+    kChooseOldestWithPriorityTestCases[] = {
+        {1, 2, false, "delayed"},
+        {1, 2, true, "immediate"},
+        {2, 1, false, "immediate"},
+        {2, 1, true, "immediate"},
+};
+
+class ChooseOldestWithPriorityTest
+    : public TaskQueueSelectorTest,
+      public testing::WithParamInterface<ChooseOldestWithPriorityTestParam> {};
+
+TEST_P(ChooseOldestWithPriorityTest, RoundRobinTest) {
+  task_queues_[0]->immediate_work_queue()->PushTaskForTest(
+      TaskQueueImpl::Task(FROM_HERE, test_closure_, base::TimeTicks(),
+                          GetParam().immediate_task_enqueue_order, true,
+                          GetParam().immediate_task_enqueue_order));
+  selector_.immediate_task_queue_sets()->OnPushQueue(
+      task_queues_[0]->immediate_work_queue());
+
+  task_queues_[0]->delayed_work_queue()->PushTaskForTest(
+      TaskQueueImpl::Task(FROM_HERE, test_closure_, base::TimeTicks(),
+                          GetParam().delayed_task_enqueue_order, true,
+                          GetParam().delayed_task_enqueue_order));
+  selector_.delayed_task_queue_sets()->OnPushQueue(
+      task_queues_[0]->delayed_work_queue());
+
+  selector_.SetForceSelectImmediateForTest(GetParam().force_select_immediate);
+
+  WorkQueue* chosen_work_queue = nullptr;
+  EXPECT_TRUE(selector_.ChooseOldestWithPriority(TaskQueue::NORMAL_PRIORITY,
+                                                 &chosen_work_queue));
+  EXPECT_EQ(chosen_work_queue->task_queue(), task_queues_[0].get());
+  EXPECT_STREQ(chosen_work_queue->name(), GetParam().expected_work_queue_name);
+}
+
+INSTANTIATE_TEST_CASE_P(ChooseOldestWithPriorityTest,
+                        ChooseOldestWithPriorityTest,
+                        testing::ValuesIn(kChooseOldestWithPriorityTestCases));
+
 }  // namespace internal
 }  // namespace scheduler
diff --git a/components/scheduler/base/task_queue_sets.cc b/components/scheduler/base/task_queue_sets.cc
deleted file mode 100644
index 9463823f..0000000
--- a/components/scheduler/base/task_queue_sets.cc
+++ /dev/null
@@ -1,96 +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.
-
-#include "components/scheduler/base/task_queue_sets.h"
-
-#include "base/logging.h"
-#include "components/scheduler/base/task_queue_impl.h"
-
-namespace scheduler {
-namespace internal {
-
-TaskQueueSets::TaskQueueSets(size_t num_sets)
-    : enqueue_order_to_queue_maps_(num_sets) {}
-
-TaskQueueSets::~TaskQueueSets() {}
-
-void TaskQueueSets::RemoveQueue(internal::TaskQueueImpl* queue) {
-  int enqueue_order;
-  bool has_enqueue_order =
-      queue->GetWorkQueueFrontTaskEnqueueOrder(&enqueue_order);
-  if (!has_enqueue_order)
-    return;
-  size_t set_index = queue->get_task_queue_set_index();
-  DCHECK_LT(set_index, enqueue_order_to_queue_maps_.size());
-  DCHECK_EQ(
-      queue,
-      enqueue_order_to_queue_maps_[set_index].find(enqueue_order)->second);
-  enqueue_order_to_queue_maps_[set_index].erase(enqueue_order);
-}
-
-void TaskQueueSets::AssignQueueToSet(internal::TaskQueueImpl* queue,
-                                     size_t set_index) {
-  DCHECK_LT(set_index, enqueue_order_to_queue_maps_.size());
-  int enqueue_order;
-  bool has_enqueue_order =
-      queue->GetWorkQueueFrontTaskEnqueueOrder(&enqueue_order);
-  size_t old_set = queue->get_task_queue_set_index();
-  DCHECK_LT(old_set, enqueue_order_to_queue_maps_.size());
-  queue->set_task_queue_set_index(set_index);
-  if (!has_enqueue_order)
-    return;
-  enqueue_order_to_queue_maps_[old_set].erase(enqueue_order);
-  enqueue_order_to_queue_maps_[set_index].insert(
-      std::make_pair(enqueue_order, queue));
-}
-
-void TaskQueueSets::OnPushQueue(internal::TaskQueueImpl* queue) {
-  int enqueue_order;
-  bool has_enqueue_order =
-      queue->GetWorkQueueFrontTaskEnqueueOrder(&enqueue_order);
-  DCHECK(has_enqueue_order);
-  size_t set_index = queue->get_task_queue_set_index();
-  DCHECK_LT(set_index, enqueue_order_to_queue_maps_.size()) << " set_index = "
-                                                            << set_index;
-  enqueue_order_to_queue_maps_[set_index].insert(
-      std::make_pair(enqueue_order, queue));
-}
-
-void TaskQueueSets::OnPopQueue(internal::TaskQueueImpl* queue) {
-  size_t set_index = queue->get_task_queue_set_index();
-  DCHECK_LT(set_index, enqueue_order_to_queue_maps_.size());
-  DCHECK(!enqueue_order_to_queue_maps_[set_index].empty()) << " set_index = "
-                                                           << set_index;
-  DCHECK_EQ(enqueue_order_to_queue_maps_[set_index].begin()->second, queue)
-      << " set_index = " << set_index;
-  // O(1) amortised.
-  enqueue_order_to_queue_maps_[set_index].erase(
-      enqueue_order_to_queue_maps_[set_index].begin());
-  int enqueue_order;
-  bool has_enqueue_order =
-      queue->GetWorkQueueFrontTaskEnqueueOrder(&enqueue_order);
-  if (!has_enqueue_order)
-    return;
-  enqueue_order_to_queue_maps_[set_index].insert(
-      std::make_pair(enqueue_order, queue));
-}
-
-bool TaskQueueSets::GetOldestQueueInSet(
-    size_t set_index,
-    internal::TaskQueueImpl** out_queue) const {
-  DCHECK_LT(set_index, enqueue_order_to_queue_maps_.size());
-  if (enqueue_order_to_queue_maps_[set_index].empty())
-    return false;
-  *out_queue = enqueue_order_to_queue_maps_[set_index].begin()->second;
-  return true;
-}
-
-bool TaskQueueSets::IsSetEmpty(size_t set_index) const {
-  DCHECK_LT(set_index, enqueue_order_to_queue_maps_.size()) << " set_index = "
-                                                            << set_index;
-  return enqueue_order_to_queue_maps_[set_index].empty();
-}
-
-}  // namespace internal
-}  // namespace scheduler
diff --git a/components/scheduler/base/task_queue_sets_unittest.cc b/components/scheduler/base/task_queue_sets_unittest.cc
deleted file mode 100644
index 8d42503a..0000000
--- a/components/scheduler/base/task_queue_sets_unittest.cc
+++ /dev/null
@@ -1,248 +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.
-
-#include "components/scheduler/base/task_queue_sets.h"
-
-#include "components/scheduler/base/task_queue_impl.h"
-#include "components/scheduler/base/virtual_time_domain.h"
-#include "testing/gmock/include/gmock/gmock.h"
-
-namespace scheduler {
-class TimeDomain;
-
-namespace internal {
-
-class TaskQueueSetsTest : public testing::Test {
- public:
-  void SetUp() override {
-    virtual_time_domain_ = make_scoped_ptr<VirtualTimeDomain>(
-        new VirtualTimeDomain(nullptr, base::TimeTicks()));
-    task_queue_sets_.reset(new TaskQueueSets(kNumSets));
-  }
-
- protected:
-  enum {
-    kNumSets = 5  // An arbitary choice.
-  };
-
-  TaskQueueImpl* NewTaskQueue(const char* queue_name) {
-    scoped_refptr<internal::TaskQueueImpl> queue =
-        make_scoped_refptr(new internal::TaskQueueImpl(
-            nullptr, virtual_time_domain_.get(), TaskQueue::Spec(queue_name),
-            "test", "test"));
-    task_queues_.push_back(queue);
-    return queue.get();
-  }
-
-  TaskQueueImpl::Task FakeTaskWithEnqueueOrder(int enqueue_order) {
-    TaskQueueImpl::Task fake_task(FROM_HERE, base::Closure(), 0, true);
-    fake_task.set_enqueue_order(enqueue_order);
-    return fake_task;
-  }
-
-  scoped_ptr<VirtualTimeDomain> virtual_time_domain_;
-  std::vector<scoped_refptr<internal::TaskQueueImpl>> task_queues_;
-  scoped_ptr<TaskQueueSets> task_queue_sets_;
-};
-
-TEST_F(TaskQueueSetsTest, AssignQueueToSet) {
-  internal::TaskQueueImpl* queue = NewTaskQueue("queue");
-  size_t set = TaskQueue::NORMAL_PRIORITY;
-  task_queue_sets_->AssignQueueToSet(queue, set);
-
-  EXPECT_EQ(set, queue->get_task_queue_set_index());
-}
-
-TEST_F(TaskQueueSetsTest, GetOldestQueueInSet_QueueEmpty) {
-  internal::TaskQueueImpl* queue = NewTaskQueue("queue");
-  size_t set = TaskQueue::NORMAL_PRIORITY;
-  task_queue_sets_->AssignQueueToSet(queue, set);
-
-  internal::TaskQueueImpl* selected_queue;
-  EXPECT_FALSE(task_queue_sets_->GetOldestQueueInSet(set, &selected_queue));
-}
-
-TEST_F(TaskQueueSetsTest, OnPushQueue) {
-  internal::TaskQueueImpl* queue = NewTaskQueue("queue");
-  size_t set = TaskQueue::NORMAL_PRIORITY;
-  task_queue_sets_->AssignQueueToSet(queue, set);
-
-  internal::TaskQueueImpl* selected_queue;
-  EXPECT_FALSE(task_queue_sets_->GetOldestQueueInSet(set, &selected_queue));
-
-  queue->PushTaskOntoWorkQueueForTest(FakeTaskWithEnqueueOrder(10));
-  task_queue_sets_->OnPushQueue(queue);
-
-  EXPECT_TRUE(task_queue_sets_->GetOldestQueueInSet(set, &selected_queue));
-  EXPECT_EQ(queue, selected_queue);
-}
-
-TEST_F(TaskQueueSetsTest, GetOldestQueueInSet_SingleTaskInSet) {
-  internal::TaskQueueImpl* queue = NewTaskQueue("queue");
-  queue->PushTaskOntoWorkQueueForTest(FakeTaskWithEnqueueOrder(10));
-  size_t set = 1;
-  task_queue_sets_->AssignQueueToSet(queue, set);
-
-  internal::TaskQueueImpl* selected_queue;
-  EXPECT_TRUE(task_queue_sets_->GetOldestQueueInSet(set, &selected_queue));
-  EXPECT_EQ(queue, selected_queue);
-}
-
-TEST_F(TaskQueueSetsTest, GetOldestQueueInSet_MultipleAgesInSet) {
-  internal::TaskQueueImpl* queue1 = NewTaskQueue("queue1");
-  internal::TaskQueueImpl* queue2 = NewTaskQueue("queue2");
-  internal::TaskQueueImpl* queue3 = NewTaskQueue("queue2");
-  queue1->PushTaskOntoWorkQueueForTest(FakeTaskWithEnqueueOrder(6));
-  queue2->PushTaskOntoWorkQueueForTest(FakeTaskWithEnqueueOrder(5));
-  queue3->PushTaskOntoWorkQueueForTest(FakeTaskWithEnqueueOrder(4));
-  size_t set = 2;
-  task_queue_sets_->AssignQueueToSet(queue1, set);
-  task_queue_sets_->AssignQueueToSet(queue2, set);
-  task_queue_sets_->AssignQueueToSet(queue3, set);
-
-  internal::TaskQueueImpl* selected_queue;
-  EXPECT_TRUE(task_queue_sets_->GetOldestQueueInSet(set, &selected_queue));
-  EXPECT_EQ(queue3, selected_queue);
-}
-
-TEST_F(TaskQueueSetsTest, OnPopQueue) {
-  internal::TaskQueueImpl* queue1 = NewTaskQueue("queue1");
-  internal::TaskQueueImpl* queue2 = NewTaskQueue("queue2");
-  internal::TaskQueueImpl* queue3 = NewTaskQueue("queue3");
-  queue1->PushTaskOntoWorkQueueForTest(FakeTaskWithEnqueueOrder(6));
-  queue2->PushTaskOntoWorkQueueForTest(FakeTaskWithEnqueueOrder(3));
-  queue2->PushTaskOntoWorkQueueForTest(FakeTaskWithEnqueueOrder(1));
-  queue3->PushTaskOntoWorkQueueForTest(FakeTaskWithEnqueueOrder(4));
-  size_t set = 3;
-  task_queue_sets_->AssignQueueToSet(queue1, set);
-  task_queue_sets_->AssignQueueToSet(queue2, set);
-  task_queue_sets_->AssignQueueToSet(queue3, set);
-
-  internal::TaskQueueImpl* selected_queue;
-  EXPECT_TRUE(task_queue_sets_->GetOldestQueueInSet(set, &selected_queue));
-  EXPECT_EQ(queue2, selected_queue);
-
-  queue2->PopTaskFromWorkQueueForTest();
-  task_queue_sets_->OnPopQueue(queue2);
-
-  EXPECT_TRUE(task_queue_sets_->GetOldestQueueInSet(set, &selected_queue));
-  EXPECT_EQ(queue2, selected_queue);
-}
-
-TEST_F(TaskQueueSetsTest, OnPopQueue_QueueBecomesEmpty) {
-  internal::TaskQueueImpl* queue1 = NewTaskQueue("queue");
-  internal::TaskQueueImpl* queue2 = NewTaskQueue("queue");
-  internal::TaskQueueImpl* queue3 = NewTaskQueue("queue");
-  queue1->PushTaskOntoWorkQueueForTest(FakeTaskWithEnqueueOrder(6));
-  queue2->PushTaskOntoWorkQueueForTest(FakeTaskWithEnqueueOrder(5));
-  queue3->PushTaskOntoWorkQueueForTest(FakeTaskWithEnqueueOrder(4));
-  size_t set = 4;
-  task_queue_sets_->AssignQueueToSet(queue1, set);
-  task_queue_sets_->AssignQueueToSet(queue2, set);
-  task_queue_sets_->AssignQueueToSet(queue3, set);
-
-  internal::TaskQueueImpl* selected_queue;
-  EXPECT_TRUE(task_queue_sets_->GetOldestQueueInSet(set, &selected_queue));
-  EXPECT_EQ(queue3, selected_queue);
-
-  queue3->PopTaskFromWorkQueueForTest();
-  task_queue_sets_->OnPopQueue(queue3);
-
-  EXPECT_TRUE(task_queue_sets_->GetOldestQueueInSet(set, &selected_queue));
-  EXPECT_EQ(queue2, selected_queue);
-}
-
-TEST_F(TaskQueueSetsTest,
-       GetOldestQueueInSet_MultipleAgesInSetIntegerRollover) {
-  internal::TaskQueueImpl* queue1 = NewTaskQueue("queue1");
-  internal::TaskQueueImpl* queue2 = NewTaskQueue("queue2");
-  internal::TaskQueueImpl* queue3 = NewTaskQueue("queue3");
-  queue1->PushTaskOntoWorkQueueForTest(FakeTaskWithEnqueueOrder(0x7ffffff1));
-  queue2->PushTaskOntoWorkQueueForTest(FakeTaskWithEnqueueOrder(0x7ffffff0));
-  queue3->PushTaskOntoWorkQueueForTest(FakeTaskWithEnqueueOrder(-0x7ffffff1));
-  size_t set = 0;
-  task_queue_sets_->AssignQueueToSet(queue1, set);
-  task_queue_sets_->AssignQueueToSet(queue2, set);
-  task_queue_sets_->AssignQueueToSet(queue3, set);
-
-  internal::TaskQueueImpl* selected_queue;
-  EXPECT_TRUE(task_queue_sets_->GetOldestQueueInSet(set, &selected_queue));
-  EXPECT_EQ(queue2, selected_queue);
-}
-
-TEST_F(TaskQueueSetsTest, GetOldestQueueInSet_MultipleAgesInSet_RemoveQueue) {
-  internal::TaskQueueImpl* queue1 = NewTaskQueue("queue1");
-  internal::TaskQueueImpl* queue2 = NewTaskQueue("queue2");
-  internal::TaskQueueImpl* queue3 = NewTaskQueue("queue3");
-  queue1->PushTaskOntoWorkQueueForTest(FakeTaskWithEnqueueOrder(6));
-  queue2->PushTaskOntoWorkQueueForTest(FakeTaskWithEnqueueOrder(5));
-  queue3->PushTaskOntoWorkQueueForTest(FakeTaskWithEnqueueOrder(4));
-  size_t set = 1;
-  task_queue_sets_->AssignQueueToSet(queue1, set);
-  task_queue_sets_->AssignQueueToSet(queue2, set);
-  task_queue_sets_->AssignQueueToSet(queue3, set);
-  task_queue_sets_->RemoveQueue(queue3);
-
-  internal::TaskQueueImpl* selected_queue;
-  EXPECT_TRUE(task_queue_sets_->GetOldestQueueInSet(set, &selected_queue));
-  EXPECT_EQ(queue2, selected_queue);
-}
-
-TEST_F(TaskQueueSetsTest, AssignQueueToSet_Complex) {
-  internal::TaskQueueImpl* queue1 = NewTaskQueue("queue1");
-  internal::TaskQueueImpl* queue2 = NewTaskQueue("queue2");
-  internal::TaskQueueImpl* queue3 = NewTaskQueue("queue3");
-  internal::TaskQueueImpl* queue4 = NewTaskQueue("queue4");
-  queue1->PushTaskOntoWorkQueueForTest(FakeTaskWithEnqueueOrder(6));
-  queue2->PushTaskOntoWorkQueueForTest(FakeTaskWithEnqueueOrder(5));
-  queue3->PushTaskOntoWorkQueueForTest(FakeTaskWithEnqueueOrder(4));
-  queue4->PushTaskOntoWorkQueueForTest(FakeTaskWithEnqueueOrder(3));
-  size_t set1 = 1;
-  size_t set2 = 2;
-  task_queue_sets_->AssignQueueToSet(queue1, set1);
-  task_queue_sets_->AssignQueueToSet(queue2, set1);
-  task_queue_sets_->AssignQueueToSet(queue3, set2);
-  task_queue_sets_->AssignQueueToSet(queue4, set2);
-
-  internal::TaskQueueImpl* selected_queue;
-  EXPECT_TRUE(task_queue_sets_->GetOldestQueueInSet(set1, &selected_queue));
-  EXPECT_EQ(queue2, selected_queue);
-
-  EXPECT_TRUE(task_queue_sets_->GetOldestQueueInSet(set2, &selected_queue));
-  EXPECT_EQ(queue4, selected_queue);
-
-  task_queue_sets_->AssignQueueToSet(queue4, set1);
-
-  EXPECT_TRUE(task_queue_sets_->GetOldestQueueInSet(set1, &selected_queue));
-  EXPECT_EQ(queue4, selected_queue);
-
-  EXPECT_TRUE(task_queue_sets_->GetOldestQueueInSet(set2, &selected_queue));
-  EXPECT_EQ(queue3, selected_queue);
-}
-
-TEST_F(TaskQueueSetsTest, IsSetEmpty_NoWork) {
-  size_t set = 0;
-  EXPECT_TRUE(task_queue_sets_->IsSetEmpty(set));
-
-  internal::TaskQueueImpl* queue = NewTaskQueue("queue");
-  task_queue_sets_->AssignQueueToSet(queue, set);
-  EXPECT_TRUE(task_queue_sets_->IsSetEmpty(set));
-}
-
-TEST_F(TaskQueueSetsTest, IsSetEmpty_Work) {
-  size_t set = 0;
-  EXPECT_TRUE(task_queue_sets_->IsSetEmpty(set));
-
-  internal::TaskQueueImpl* queue = NewTaskQueue("queue");
-  queue->PushTaskOntoWorkQueueForTest(FakeTaskWithEnqueueOrder(1));
-  task_queue_sets_->AssignQueueToSet(queue, set);
-  EXPECT_FALSE(task_queue_sets_->IsSetEmpty(set));
-
-  queue->PopTaskFromWorkQueueForTest();
-  task_queue_sets_->OnPopQueue(queue);
-  EXPECT_TRUE(task_queue_sets_->IsSetEmpty(set));
-}
-
-}  // namespace internal
-}  // namespace scheduler
diff --git a/components/scheduler/base/time_domain.cc b/components/scheduler/base/time_domain.cc
index e64b4e9..e23883e 100644
--- a/components/scheduler/base/time_domain.cc
+++ b/components/scheduler/base/time_domain.cc
@@ -8,6 +8,7 @@
 
 #include "components/scheduler/base/task_queue_impl.h"
 #include "components/scheduler/base/task_queue_manager_delegate.h"
+#include "components/scheduler/base/work_queue.h"
 #include "components/scheduler/scheduler_export.h"
 
 namespace scheduler {
@@ -125,8 +126,8 @@
   DCHECK(main_thread_checker_.CalledOnValidThread());
   LazyNow lazy_now(CreateLazyNow());
 
-  // Move any ready delayed tasks into the incomming queues.
-  WakeupReadyDelayedQueues(&lazy_now);
+  // Move any ready delayed tasks into the Incoming queues.
+  WakeupReadyDelayedQueues(&lazy_now, should_trigger_wakeup, previous_task);
 
   MoveNewlyUpdatableQueuesIntoUpdatableQueueSet();
 
@@ -136,8 +137,8 @@
     // NOTE Update work queue may erase itself from |updatable_queue_set_|.
     // This is fine, erasing an element won't invalidate any interator, as long
     // as the iterator isn't the element being delated.
-    if (queue->work_queue().empty())
-      queue->UpdateWorkQueue(&lazy_now, should_trigger_wakeup, previous_task);
+    if (queue->immediate_work_queue()->Empty())
+      queue->UpdateImmediateWorkQueue(should_trigger_wakeup, previous_task);
   }
 }
 
@@ -150,7 +151,10 @@
   }
 }
 
-void TimeDomain::WakeupReadyDelayedQueues(LazyNow* lazy_now) {
+void TimeDomain::WakeupReadyDelayedQueues(
+    LazyNow* lazy_now,
+    bool should_trigger_wakeup,
+    const internal::TaskQueueImpl::Task* previous_task) {
   // Wake up any queues with pending delayed work.  Note std::multipmap stores
   // the elements sorted by key, so the begin() iterator points to the earliest
   // queue to wakeup.
@@ -161,12 +165,14 @@
     if (next_wakeup->first > lazy_now->Now())
       break;
     // A queue could have any number of delayed tasks pending so it's worthwhile
-    // deduping calls to MoveReadyDelayedTasksToIncomingQueue since it takes a
-    // lock.  NOTE the order in which these are called matters since the order
+    // deduping calls to UpdateDelayedWorkQueue since it takes a lock.
+    // NOTE the order in which these are called matters since the order
     // in which EnqueueTaskLocks is called is respected when choosing which
     // queue to execute a task from.
-    if (dedup_set.insert(next_wakeup->second).second)
-      next_wakeup->second->MoveReadyDelayedTasksToIncomingQueue(lazy_now);
+    if (dedup_set.insert(next_wakeup->second).second) {
+      next_wakeup->second->UpdateDelayedWorkQueue(
+          lazy_now, should_trigger_wakeup, previous_task);
+    }
     delayed_wakeup_multimap_.erase(next_wakeup);
   }
 }
diff --git a/components/scheduler/base/time_domain.h b/components/scheduler/base/time_domain.h
index 5cf39b70..e8691f3 100644
--- a/components/scheduler/base/time_domain.h
+++ b/components/scheduler/base/time_domain.h
@@ -76,7 +76,7 @@
   // UpdateWorkQueue on.
   void RegisterAsUpdatableTaskQueue(internal::TaskQueueImpl* queue);
 
-  // Schedules a call to TaskQueueImpl::MoveReadyDelayedTasksToIncomingQueue
+  // Schedules a call to TaskQueueImpl::MoveReadyDelayedTasksToDelayedWorkQueue
   // when this TimeDomain reaches |delayed_run_time|.
   void ScheduleDelayedWork(internal::TaskQueueImpl* queue,
                            base::TimeTicks delayed_run_time,
@@ -98,20 +98,22 @@
 
   // Called by the TaskQueueManager when the TimeDomain is registered.
   virtual void OnRegisterWithTaskQueueManager(
-      TaskQueueManagerDelegate* task_queue_manager_delegate,
-      base::Closure do_work_closure) = 0;
+      TaskQueueManager* task_queue_manager) = 0;
 
   // The implementaion will secedule task processing to run with |delay| with
-  // respect to the TimeDomain's time source.
+  // respect to the TimeDomain's time source.  Always called on the main thread.
   virtual void RequestWakeup(LazyNow* lazy_now, base::TimeDelta delay) = 0;
 
   // For implementation specific tracing.
   virtual void AsValueIntoInternal(
       base::trace_event::TracedValue* state) const = 0;
 
-  // Call TaskQueueImpl::MoveReadyDelayedTasksToIncomingQueue for each
-  // queue where the delay has elapsed.
-  void WakeupReadyDelayedQueues(LazyNow* lazy_now);
+  // Call TaskQueueImpl::UpdateDelayedWorkQueue for each queue where the delay
+  // has elapsed.
+  void WakeupReadyDelayedQueues(
+      LazyNow* lazy_now,
+      bool should_trigger_wakeup,
+      const internal::TaskQueueImpl::Task* previous_task);
 
  private:
   void MoveNewlyUpdatableQueuesIntoUpdatableQueueSet();
diff --git a/components/scheduler/base/time_domain_unittest.cc b/components/scheduler/base/time_domain_unittest.cc
index e699e18..568d373 100644
--- a/components/scheduler/base/time_domain_unittest.cc
+++ b/components/scheduler/base/time_domain_unittest.cc
@@ -10,6 +10,7 @@
 #include "components/scheduler/base/task_queue_manager.h"
 #include "components/scheduler/base/task_queue_manager_delegate_for_test.h"
 #include "components/scheduler/base/test_time_source.h"
+#include "components/scheduler/base/work_queue.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
 using testing::_;
@@ -41,8 +42,7 @@
   bool MaybeAdvanceTime() override { return false; }
   const char* GetName() const override { return "Test"; }
   void OnRegisterWithTaskQueueManager(
-      TaskQueueManagerDelegate* task_queue_manager_delegate,
-      base::Closure do_work_closure) override {}
+      TaskQueueManager* task_queue_manager) override {}
 
   MOCK_METHOD2(RequestWakeup, void(LazyNow* lazy_now, base::TimeDelta delay));
 
@@ -159,14 +159,14 @@
       task_queue_manager.NewTaskQueue(TaskQueue::Spec("test_queue"));
 
   // Post a delayed task on |dummy_queue| and advance the queue's clock so that
-  // next time MoveReadyDelayedTasksToIncomingQueue is called, the task will
-  // get moved onto the incomming queue.
+  // next time MoveReadyDelayedTasksToDelayedWorkQueue is called, the task will
+  // get moved onto the Incoming queue.
   base::TimeDelta dummy_delay = base::TimeDelta::FromMilliseconds(10);
   dummy_queue->PostDelayedTask(FROM_HERE, base::Closure(), dummy_delay);
   dummy_time_source.Advance(dummy_delay);
 
   // Now we can test that ScheduleDelayedWork triggers calls to
-  // MoveReadyDelayedTasksToIncomingQueue as expected.
+  // MoveReadyDelayedTasksToDelayedWorkQueue as expected.
   base::TimeDelta delay = base::TimeDelta::FromMilliseconds(50);
   base::TimeTicks delayed_runtime = time_domain_->Now() + delay;
   EXPECT_CALL(*time_domain_.get(), RequestWakeup(_, delay));
@@ -175,11 +175,11 @@
                                     &lazy_now);
 
   time_domain_->UpdateWorkQueues(false, nullptr);
-  EXPECT_EQ(0UL, dummy_queue->IncomingQueueSizeForTest());
+  EXPECT_EQ(0UL, dummy_queue->delayed_work_queue()->Size());
 
   time_domain_->SetNow(delayed_runtime);
   time_domain_->UpdateWorkQueues(false, nullptr);
-  EXPECT_EQ(1UL, dummy_queue->IncomingQueueSizeForTest());
+  EXPECT_EQ(1UL, dummy_queue->delayed_work_queue()->Size());
 }
 
 namespace {
diff --git a/components/scheduler/base/virtual_time_domain.cc b/components/scheduler/base/virtual_time_domain.cc
index 0ed6abb..0abea94 100644
--- a/components/scheduler/base/virtual_time_domain.cc
+++ b/components/scheduler/base/virtual_time_domain.cc
@@ -6,22 +6,21 @@
 
 #include "base/bind.h"
 #include "components/scheduler/base/task_queue_impl.h"
+#include "components/scheduler/base/task_queue_manager.h"
 #include "components/scheduler/base/task_queue_manager_delegate.h"
 
 namespace scheduler {
 
 VirtualTimeDomain::VirtualTimeDomain(TimeDomain::Observer* observer,
                                      base::TimeTicks initial_time)
-    : TimeDomain(observer), now_(initial_time) {}
+    : TimeDomain(observer), now_(initial_time), task_queue_manager_(nullptr) {}
 
 VirtualTimeDomain::~VirtualTimeDomain() {}
 
 void VirtualTimeDomain::OnRegisterWithTaskQueueManager(
-    TaskQueueManagerDelegate* task_queue_manager_delegate,
-    base::Closure do_work_closure) {
-  task_queue_manager_delegate_ = task_queue_manager_delegate;
-  do_work_closure_ = do_work_closure;
-  DCHECK(task_queue_manager_delegate_);
+    TaskQueueManager* task_queue_manager) {
+  task_queue_manager_ = task_queue_manager;
+  DCHECK(task_queue_manager_);
 }
 
 LazyNow VirtualTimeDomain::CreateLazyNow() {
@@ -31,7 +30,9 @@
 
 void VirtualTimeDomain::RequestWakeup(LazyNow* lazy_now,
                                       base::TimeDelta delay) {
-  // We don't need to do anything here because AdvanceTo posts a DoWork.
+  // We don't need to do anything here because the caller of AdvanceTo is
+  // responsible for calling TaskQueueManager::MaybeScheduleImmediateWork if
+  // needed.
 }
 
 bool VirtualTimeDomain::MaybeAdvanceTime() {
@@ -45,9 +46,10 @@
   base::AutoLock lock(lock_);
   DCHECK_GE(now, now_);
   now_ = now;
-  DCHECK(task_queue_manager_delegate_);
+}
 
-  task_queue_manager_delegate_->PostTask(FROM_HERE, do_work_closure_);
+void VirtualTimeDomain::RequestDoWork() {
+  task_queue_manager_->MaybeScheduleImmediateWork(FROM_HERE);
 }
 
 const char* VirtualTimeDomain::GetName() const {
diff --git a/components/scheduler/base/virtual_time_domain.h b/components/scheduler/base/virtual_time_domain.h
index 78239c1c..0242a62 100644
--- a/components/scheduler/base/virtual_time_domain.h
+++ b/components/scheduler/base/virtual_time_domain.h
@@ -11,7 +11,6 @@
 #include "components/scheduler/scheduler_export.h"
 
 namespace scheduler {
-class TaskQueueManagerDelegate;
 
 class SCHEDULER_EXPORT VirtualTimeDomain : public TimeDomain {
  public:
@@ -25,22 +24,24 @@
   const char* GetName() const override;
 
   // Advances this time domain to |now|. NOTE |now| is supposed to be
-  // monotonically increasing.
+  // monotonically increasing.  NOTE it's the responsibility of the caller to
+  // call TaskQueueManager::MaybeScheduleImmediateWork if needed.
   void AdvanceTo(base::TimeTicks now);
 
  protected:
   void OnRegisterWithTaskQueueManager(
-      TaskQueueManagerDelegate* task_queue_manager_delegate,
-      base::Closure do_work_closure) override;
+      TaskQueueManager* task_queue_manager) override;
   void RequestWakeup(LazyNow* lazy_now, base::TimeDelta delay) override;
   void AsValueIntoInternal(
       base::trace_event::TracedValue* state) const override;
 
+  void RequestDoWork();
+
  private:
   mutable base::Lock lock_;  // Protects |now_|.
   base::TimeTicks now_;
 
-  TaskQueueManagerDelegate* task_queue_manager_delegate_;  // NOT OWNED
+  TaskQueueManager* task_queue_manager_;  // NOT OWNED
   base::Closure do_work_closure_;
 
   DISALLOW_COPY_AND_ASSIGN(VirtualTimeDomain);
diff --git a/components/scheduler/base/work_queue.cc b/components/scheduler/base/work_queue.cc
new file mode 100644
index 0000000..1e46c42b
--- /dev/null
+++ b/components/scheduler/base/work_queue.cc
@@ -0,0 +1,84 @@
+// 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.
+
+#include "components/scheduler/base/work_queue.h"
+
+#include "components/scheduler/base/work_queue_sets.h"
+
+namespace scheduler {
+namespace internal {
+
+WorkQueue::WorkQueue(WorkQueueSets* task_queue_sets,
+                     TaskQueueImpl* task_queue,
+                     const char* name)
+    : work_queue_sets_(task_queue_sets),
+      task_queue_(task_queue),
+      work_queue_set_index_(0),
+      name_(name) {}
+
+void WorkQueue::AsValueInto(base::trace_event::TracedValue* state) const {
+  std::queue<TaskQueueImpl::Task> queue_copy(work_queue_);
+  while (!queue_copy.empty()) {
+    TaskQueueImpl::TaskAsValueInto(queue_copy.front(), state);
+    queue_copy.pop();
+  }
+}
+
+WorkQueue::~WorkQueue() {}
+
+void WorkQueue::Clear() {
+  work_queue_ = std::queue<TaskQueueImpl::Task>();
+}
+
+bool WorkQueue::GetFrontTaskEnqueueOrder(int* enqueue_order) const {
+  if (work_queue_.empty())
+    return false;
+  *enqueue_order = work_queue_.front().enqueue_order();
+  return true;
+}
+
+void WorkQueue::Push(const TaskQueueImpl::Task&& task) {
+  bool was_empty = work_queue_.empty();
+  work_queue_.push(task);
+  if (was_empty)
+    work_queue_sets_->OnPushQueue(this);
+}
+
+void WorkQueue::PushTaskForTest(const TaskQueueImpl::Task&& task) {
+  work_queue_.push(task);
+}
+
+void WorkQueue::PushAndSetEnqueueOrder(const TaskQueueImpl::Task&& task,
+                                       int enqueue_order) {
+  bool was_empty = work_queue_.empty();
+  work_queue_.push(task);
+  work_queue_.back().set_enqueue_order(enqueue_order);
+
+  if (was_empty)
+    work_queue_sets_->OnPushQueue(this);
+}
+
+void WorkQueue::PopTaskForTest() {
+  work_queue_.pop();
+}
+
+void WorkQueue::Swap(std::queue<TaskQueueImpl::Task>& incoming_queue) {
+  std::swap(work_queue_, incoming_queue);
+
+  if (!work_queue_.empty())
+    work_queue_sets_->OnPushQueue(this);
+  task_queue_->TraceQueueSize(false);
+}
+
+TaskQueueImpl::Task WorkQueue::TakeTaskFromWorkQueue() {
+  DCHECK(!work_queue_.empty());
+  TaskQueueImpl::Task pending_task = std::move(work_queue_.front());
+  work_queue_.pop();
+  work_queue_sets_->OnPopQueue(this);
+  task_queue_->TraceQueueSize(false);
+  return pending_task;
+}
+
+}  // namespace internal
+}  // namespace scheduler
diff --git a/components/scheduler/base/work_queue.h b/components/scheduler/base/work_queue.h
new file mode 100644
index 0000000..635766f9
--- /dev/null
+++ b/components/scheduler/base/work_queue.h
@@ -0,0 +1,82 @@
+// 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.
+
+#ifndef CONTENT_RENDERER_SCHEDULER_BASE_WORK_QUEUE_H_
+#define CONTENT_RENDERER_SCHEDULER_BASE_WORK_QUEUE_H_
+
+#include <set>
+
+#include "base/trace_event/trace_event.h"
+#include "base/trace_event/trace_event_argument.h"
+#include "components/scheduler/base/task_queue_impl.h"
+#include "components/scheduler/scheduler_export.h"
+
+namespace scheduler {
+namespace internal {
+class WorkQueueSets;
+
+class SCHEDULER_EXPORT WorkQueue {
+ public:
+  WorkQueue(WorkQueueSets* task_queue_sets,
+            TaskQueueImpl* task_queue,
+            const char* name);
+  ~WorkQueue();
+
+  void AsValueInto(base::trace_event::TracedValue* state) const;
+
+  // Clears the |work_queue_|.
+  void Clear();
+
+  // returns true if the |work_queue_| is empty.
+  bool Empty() const { return work_queue_.empty(); }
+
+  // If the |work_queue_| isn't empty, |enqueue_order| gets set to the enqueue
+  // order of the front task and the function returns true.  Otherwise the
+  // function returns false.
+  bool GetFrontTaskEnqueueOrder(int* enqueue_order) const;
+
+  // Pushes the task onto the |work_queue_| and informs the WorkQueueSets if
+  // the head changed.
+  void Push(const TaskQueueImpl::Task&& task);
+
+  // Pushes the task onto the |work_queue_|, sets the |enqueue_order| and
+  // informs the WorkQueueSets if the head changed.
+  void PushAndSetEnqueueOrder(const TaskQueueImpl::Task&& task,
+                              int enqueue_order);
+
+  // Swap the |work_queue_| with |incoming_queue| and informs the
+  // WorkQueueSets if the head changed.
+  void Swap(std::queue<TaskQueueImpl::Task>& incoming_queue);
+
+  size_t Size() const { return work_queue_.size(); }
+
+  // Pulls a task off the |work_queue_| and informs the WorkQueueSets.
+  TaskQueueImpl::Task TakeTaskFromWorkQueue();
+
+  const char* name() const { return name_; }
+
+  TaskQueueImpl* task_queue() const { return task_queue_; }
+
+  size_t work_queue_set_index() const { return work_queue_set_index_; }
+
+  void set_work_queue_set_index(size_t work_queue_set_index) {
+    work_queue_set_index_ = work_queue_set_index;
+  }
+
+  // Test support functions.  These should not be used in production code.
+  void PopTaskForTest();
+  void PushTaskForTest(const TaskQueueImpl::Task&& task);
+
+ private:
+  std::queue<TaskQueueImpl::Task> work_queue_;
+  WorkQueueSets* work_queue_sets_;  // NOT OWNED.
+  TaskQueueImpl* task_queue_;       // NOT OWNED.
+  size_t work_queue_set_index_;
+  const char* name_;
+};
+
+}  // namespace internal
+}  // namespace scheduler
+
+#endif  // CONTENT_RENDERER_SCHEDULER_BASE_WORK_QUEUE_H_
diff --git a/components/scheduler/base/work_queue_sets.cc b/components/scheduler/base/work_queue_sets.cc
new file mode 100644
index 0000000..b4a9d5a
--- /dev/null
+++ b/components/scheduler/base/work_queue_sets.cc
@@ -0,0 +1,92 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/scheduler/base/work_queue_sets.h"
+
+#include "base/logging.h"
+#include "components/scheduler/base/work_queue.h"
+
+namespace scheduler {
+namespace internal {
+
+WorkQueueSets::WorkQueueSets(size_t num_sets)
+    : enqueue_order_to_work_queue_maps_(num_sets) {}
+
+WorkQueueSets::~WorkQueueSets() {}
+
+void WorkQueueSets::RemoveQueue(WorkQueue* work_queue) {
+  int enqueue_order;
+  bool has_enqueue_order = work_queue->GetFrontTaskEnqueueOrder(&enqueue_order);
+  if (!has_enqueue_order)
+    return;
+  size_t set_index = work_queue->work_queue_set_index();
+  DCHECK_LT(set_index, enqueue_order_to_work_queue_maps_.size());
+  DCHECK_EQ(
+      work_queue,
+      enqueue_order_to_work_queue_maps_[set_index].find(enqueue_order)->second);
+  enqueue_order_to_work_queue_maps_[set_index].erase(enqueue_order);
+}
+
+void WorkQueueSets::AssignQueueToSet(WorkQueue* work_queue, size_t set_index) {
+  DCHECK_LT(set_index, enqueue_order_to_work_queue_maps_.size());
+  int enqueue_order;
+  bool has_enqueue_order = work_queue->GetFrontTaskEnqueueOrder(&enqueue_order);
+  size_t old_set = work_queue->work_queue_set_index();
+  DCHECK_LT(old_set, enqueue_order_to_work_queue_maps_.size());
+  work_queue->set_work_queue_set_index(set_index);
+  if (!has_enqueue_order)
+    return;
+  enqueue_order_to_work_queue_maps_[old_set].erase(enqueue_order);
+  enqueue_order_to_work_queue_maps_[set_index].insert(
+      std::make_pair(enqueue_order, work_queue));
+}
+
+void WorkQueueSets::OnPushQueue(WorkQueue* work_queue) {
+  int enqueue_order;
+  bool has_enqueue_order = work_queue->GetFrontTaskEnqueueOrder(&enqueue_order);
+  DCHECK(has_enqueue_order);
+  size_t set_index = work_queue->work_queue_set_index();
+  DCHECK_LT(set_index, enqueue_order_to_work_queue_maps_.size())
+      << " set_index = " << set_index;
+  enqueue_order_to_work_queue_maps_[set_index].insert(
+      std::make_pair(enqueue_order, work_queue));
+}
+
+void WorkQueueSets::OnPopQueue(WorkQueue* work_queue) {
+  size_t set_index = work_queue->work_queue_set_index();
+  DCHECK_LT(set_index, enqueue_order_to_work_queue_maps_.size());
+  DCHECK(!enqueue_order_to_work_queue_maps_[set_index].empty())
+      << " set_index = " << set_index;
+  DCHECK_EQ(enqueue_order_to_work_queue_maps_[set_index].begin()->second,
+            work_queue)
+      << " set_index = " << set_index;
+  // O(1) amortised.
+  enqueue_order_to_work_queue_maps_[set_index].erase(
+      enqueue_order_to_work_queue_maps_[set_index].begin());
+  int enqueue_order;
+  bool has_enqueue_order = work_queue->GetFrontTaskEnqueueOrder(&enqueue_order);
+  if (!has_enqueue_order)
+    return;
+  enqueue_order_to_work_queue_maps_[set_index].insert(
+      std::make_pair(enqueue_order, work_queue));
+}
+
+bool WorkQueueSets::GetOldestQueueInSet(size_t set_index,
+                                        WorkQueue** out_work_queue) const {
+  DCHECK_LT(set_index, enqueue_order_to_work_queue_maps_.size());
+  if (enqueue_order_to_work_queue_maps_[set_index].empty())
+    return false;
+  *out_work_queue =
+      enqueue_order_to_work_queue_maps_[set_index].begin()->second;
+  return true;
+}
+
+bool WorkQueueSets::IsSetEmpty(size_t set_index) const {
+  DCHECK_LT(set_index, enqueue_order_to_work_queue_maps_.size())
+      << " set_index = " << set_index;
+  return enqueue_order_to_work_queue_maps_[set_index].empty();
+}
+
+}  // namespace internal
+}  // namespace scheduler
diff --git a/components/scheduler/base/task_queue_sets.h b/components/scheduler/base/work_queue_sets.h
similarity index 62%
rename from components/scheduler/base/task_queue_sets.h
rename to components/scheduler/base/work_queue_sets.h
index e3b17ec..9e7c569 100644
--- a/components/scheduler/base/task_queue_sets.h
+++ b/components/scheduler/base/work_queue_sets.h
@@ -2,46 +2,48 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef COMPONENTS_SCHEDULER_BASE_TASK_QUEUE_SETS_H_
-#define COMPONENTS_SCHEDULER_BASE_TASK_QUEUE_SETS_H_
+#ifndef COMPONENTS_SCHEDULER_BASE_WORK_QUEUE_SETS_H_
+#define COMPONENTS_SCHEDULER_BASE_WORK_QUEUE_SETS_H_
 
 #include <map>
 #include <vector>
 
 #include "base/macros.h"
 #include "base/trace_event/trace_event_argument.h"
-#include "components/scheduler/base/task_queue.h"
+#include "components/scheduler/base/task_queue_impl.h"
 #include "components/scheduler/scheduler_export.h"
 
 namespace scheduler {
 namespace internal {
 class TaskQueueImpl;
 
-class SCHEDULER_EXPORT TaskQueueSets {
+class SCHEDULER_EXPORT WorkQueueSets {
  public:
-  explicit TaskQueueSets(size_t num_sets);
-  ~TaskQueueSets();
+  explicit WorkQueueSets(size_t num_sets);
+  ~WorkQueueSets();
 
   // O(log num queues)
-  void RemoveQueue(internal::TaskQueueImpl* queue);
+  void RemoveQueue(WorkQueue* work_queue);
 
   // O(log num queues)
-  void AssignQueueToSet(internal::TaskQueueImpl* queue, size_t set_index);
+  void AssignQueueToSet(WorkQueue* queue, size_t set_index);
 
   // O(log num queues)
-  void OnPushQueue(internal::TaskQueueImpl* queue);
+  void OnPushQueue(WorkQueue* work_queue);
 
   // If empty it's O(1) amortized, otherwise it's O(log num queues)
-  void OnPopQueue(internal::TaskQueueImpl* queue);
+  void OnPopQueue(WorkQueue* work_queue);
 
   // O(1)
-  bool GetOldestQueueInSet(size_t set_index,
-                           internal::TaskQueueImpl** out_queue) const;
+  bool GetOldestQueueInSet(size_t set_index, WorkQueue** out_work_queue) const;
 
   // O(1)
   bool IsSetEmpty(size_t set_index) const;
 
  private:
+  bool GetWorkQueueFrontTaskEnqueueOrder(WorkQueue* work_queue,
+                                         int* enqueue_order) const;
+
   struct EnqueueOrderComparitor {
     // The enqueueorder numbers are generated in sequence.  These will
     // eventually overflow and roll-over to negative numbers.  We must take care
@@ -62,14 +64,14 @@
     }
   };
 
-  typedef std::map<int, internal::TaskQueueImpl*, EnqueueOrderComparitor>
-      EnqueueOrderToQueueMap;
-  std::vector<EnqueueOrderToQueueMap> enqueue_order_to_queue_maps_;
+  typedef std::map<int, WorkQueue*, EnqueueOrderComparitor>
+      EnqueueOrderToWorkQueueMap;
+  std::vector<EnqueueOrderToWorkQueueMap> enqueue_order_to_work_queue_maps_;
 
-  DISALLOW_COPY_AND_ASSIGN(TaskQueueSets);
+  DISALLOW_COPY_AND_ASSIGN(WorkQueueSets);
 };
 
 }  // namespace internal
 }  // namespace scheduler
 
-#endif  // COMPONENTS_SCHEDULER_BASE_TASK_QUEUE_SETS_H_
+#endif  // COMPONENTS_SCHEDULER_BASE_WORK_QUEUE_SETS_H_
diff --git a/components/scheduler/base/work_queue_sets_unittest.cc b/components/scheduler/base/work_queue_sets_unittest.cc
new file mode 100644
index 0000000..c5aef58
--- /dev/null
+++ b/components/scheduler/base/work_queue_sets_unittest.cc
@@ -0,0 +1,246 @@
+// 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.
+
+#include "components/scheduler/base/work_queue_sets.h"
+
+#include "components/scheduler/base/work_queue.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace scheduler {
+class TimeDomain;
+
+namespace internal {
+
+class WorkQueueSetsTest : public testing::Test {
+ public:
+  void SetUp() override { work_queue_sets_.reset(new WorkQueueSets(kNumSets)); }
+
+ protected:
+  enum {
+    kNumSets = 5  // An arbitary choice.
+  };
+
+  WorkQueue* NewTaskQueue(const char* queue_name) {
+    WorkQueue* queue = new WorkQueue(work_queue_sets_.get(), nullptr, "test");
+    work_queues_.push_back(make_scoped_ptr(queue));
+    return queue;
+  }
+
+  TaskQueueImpl::Task FakeTaskWithEnqueueOrder(int enqueue_order) {
+    TaskQueueImpl::Task fake_task(FROM_HERE, base::Closure(), base::TimeTicks(),
+                                  0, true);
+    fake_task.set_enqueue_order(enqueue_order);
+    return fake_task;
+  }
+
+  std::vector<scoped_ptr<WorkQueue>> work_queues_;
+  scoped_ptr<WorkQueueSets> work_queue_sets_;
+};
+
+TEST_F(WorkQueueSetsTest, AssignQueueToSet) {
+  WorkQueue* work_queue = NewTaskQueue("queue");
+  size_t set = TaskQueue::NORMAL_PRIORITY;
+  work_queue_sets_->AssignQueueToSet(work_queue, set);
+
+  EXPECT_EQ(set, work_queue->work_queue_set_index());
+}
+
+TEST_F(WorkQueueSetsTest, GetOldestQueueInSet_QueueEmpty) {
+  WorkQueue* work_queue = NewTaskQueue("queue");
+  size_t set = TaskQueue::NORMAL_PRIORITY;
+  work_queue_sets_->AssignQueueToSet(work_queue, set);
+
+  WorkQueue* selected_work_queue;
+  EXPECT_FALSE(
+      work_queue_sets_->GetOldestQueueInSet(set, &selected_work_queue));
+}
+
+TEST_F(WorkQueueSetsTest, OnPushQueue) {
+  WorkQueue* work_queue = NewTaskQueue("queue");
+  size_t set = TaskQueue::NORMAL_PRIORITY;
+  work_queue_sets_->AssignQueueToSet(work_queue, set);
+
+  WorkQueue* selected_work_queue;
+  EXPECT_FALSE(
+      work_queue_sets_->GetOldestQueueInSet(set, &selected_work_queue));
+
+  work_queue->Push(FakeTaskWithEnqueueOrder(10));
+  work_queue_sets_->OnPushQueue(work_queue);
+
+  EXPECT_TRUE(work_queue_sets_->GetOldestQueueInSet(set, &selected_work_queue));
+  EXPECT_EQ(work_queue, selected_work_queue);
+}
+
+TEST_F(WorkQueueSetsTest, GetOldestQueueInSet_SingleTaskInSet) {
+  WorkQueue* work_queue = NewTaskQueue("queue");
+  work_queue->Push(FakeTaskWithEnqueueOrder(10));
+  size_t set = 1;
+  work_queue_sets_->AssignQueueToSet(work_queue, set);
+
+  WorkQueue* selected_work_queue;
+  EXPECT_TRUE(work_queue_sets_->GetOldestQueueInSet(set, &selected_work_queue));
+  EXPECT_EQ(work_queue, selected_work_queue);
+}
+
+TEST_F(WorkQueueSetsTest, GetOldestQueueInSet_MultipleAgesInSet) {
+  WorkQueue* queue1 = NewTaskQueue("queue1");
+  WorkQueue* queue2 = NewTaskQueue("queue2");
+  WorkQueue* queue3 = NewTaskQueue("queue2");
+  queue1->Push(FakeTaskWithEnqueueOrder(6));
+  queue2->Push(FakeTaskWithEnqueueOrder(5));
+  queue3->Push(FakeTaskWithEnqueueOrder(4));
+  size_t set = 2;
+  work_queue_sets_->AssignQueueToSet(queue1, set);
+  work_queue_sets_->AssignQueueToSet(queue2, set);
+  work_queue_sets_->AssignQueueToSet(queue3, set);
+
+  WorkQueue* selected_work_queue;
+  EXPECT_TRUE(work_queue_sets_->GetOldestQueueInSet(set, &selected_work_queue));
+  EXPECT_EQ(queue3, selected_work_queue);
+}
+
+TEST_F(WorkQueueSetsTest, OnPopQueue) {
+  WorkQueue* queue1 = NewTaskQueue("queue1");
+  WorkQueue* queue2 = NewTaskQueue("queue2");
+  WorkQueue* queue3 = NewTaskQueue("queue3");
+  queue1->Push(FakeTaskWithEnqueueOrder(6));
+  queue2->Push(FakeTaskWithEnqueueOrder(3));
+  queue2->Push(FakeTaskWithEnqueueOrder(1));
+  queue3->Push(FakeTaskWithEnqueueOrder(4));
+  size_t set = 3;
+  work_queue_sets_->AssignQueueToSet(queue1, set);
+  work_queue_sets_->AssignQueueToSet(queue2, set);
+  work_queue_sets_->AssignQueueToSet(queue3, set);
+
+  WorkQueue* selected_work_queue;
+  EXPECT_TRUE(work_queue_sets_->GetOldestQueueInSet(set, &selected_work_queue));
+  EXPECT_EQ(queue2, selected_work_queue);
+
+  queue2->PopTaskForTest();
+  work_queue_sets_->OnPopQueue(queue2);
+
+  EXPECT_TRUE(work_queue_sets_->GetOldestQueueInSet(set, &selected_work_queue));
+  EXPECT_EQ(queue2, selected_work_queue);
+}
+
+TEST_F(WorkQueueSetsTest, OnPopQueue_QueueBecomesEmpty) {
+  WorkQueue* queue1 = NewTaskQueue("queue");
+  WorkQueue* queue2 = NewTaskQueue("queue");
+  WorkQueue* queue3 = NewTaskQueue("queue");
+  queue1->Push(FakeTaskWithEnqueueOrder(6));
+  queue2->Push(FakeTaskWithEnqueueOrder(5));
+  queue3->Push(FakeTaskWithEnqueueOrder(4));
+  size_t set = 4;
+  work_queue_sets_->AssignQueueToSet(queue1, set);
+  work_queue_sets_->AssignQueueToSet(queue2, set);
+  work_queue_sets_->AssignQueueToSet(queue3, set);
+
+  WorkQueue* selected_work_queue;
+  EXPECT_TRUE(work_queue_sets_->GetOldestQueueInSet(set, &selected_work_queue));
+  EXPECT_EQ(queue3, selected_work_queue);
+
+  queue3->PopTaskForTest();
+  work_queue_sets_->OnPopQueue(queue3);
+
+  EXPECT_TRUE(work_queue_sets_->GetOldestQueueInSet(set, &selected_work_queue));
+  EXPECT_EQ(queue2, selected_work_queue);
+}
+
+TEST_F(WorkQueueSetsTest,
+       GetOldestQueueInSet_MultipleAgesInSetIntegerRollover) {
+  WorkQueue* queue1 = NewTaskQueue("queue1");
+  WorkQueue* queue2 = NewTaskQueue("queue2");
+  WorkQueue* queue3 = NewTaskQueue("queue3");
+  queue1->Push(FakeTaskWithEnqueueOrder(0x7ffffff1));
+  queue2->Push(FakeTaskWithEnqueueOrder(0x7ffffff0));
+  queue3->Push(FakeTaskWithEnqueueOrder(-0x7ffffff1));
+  size_t set = 0;
+  work_queue_sets_->AssignQueueToSet(queue1, set);
+  work_queue_sets_->AssignQueueToSet(queue2, set);
+  work_queue_sets_->AssignQueueToSet(queue3, set);
+
+  WorkQueue* selected_work_queue;
+  EXPECT_TRUE(work_queue_sets_->GetOldestQueueInSet(set, &selected_work_queue));
+  EXPECT_EQ(queue2, selected_work_queue);
+}
+
+TEST_F(WorkQueueSetsTest, GetOldestQueueInSet_MultipleAgesInSet_RemoveQueue) {
+  WorkQueue* queue1 = NewTaskQueue("queue1");
+  WorkQueue* queue2 = NewTaskQueue("queue2");
+  WorkQueue* queue3 = NewTaskQueue("queue3");
+  queue1->Push(FakeTaskWithEnqueueOrder(6));
+  queue2->Push(FakeTaskWithEnqueueOrder(5));
+  queue3->Push(FakeTaskWithEnqueueOrder(4));
+  size_t set = 1;
+  work_queue_sets_->AssignQueueToSet(queue1, set);
+  work_queue_sets_->AssignQueueToSet(queue2, set);
+  work_queue_sets_->AssignQueueToSet(queue3, set);
+  work_queue_sets_->RemoveQueue(queue3);
+
+  WorkQueue* selected_work_queue;
+  EXPECT_TRUE(work_queue_sets_->GetOldestQueueInSet(set, &selected_work_queue));
+  EXPECT_EQ(queue2, selected_work_queue);
+}
+
+TEST_F(WorkQueueSetsTest, AssignQueueToSet_Complex) {
+  WorkQueue* queue1 = NewTaskQueue("queue1");
+  WorkQueue* queue2 = NewTaskQueue("queue2");
+  WorkQueue* queue3 = NewTaskQueue("queue3");
+  WorkQueue* queue4 = NewTaskQueue("queue4");
+  queue1->Push(FakeTaskWithEnqueueOrder(6));
+  queue2->Push(FakeTaskWithEnqueueOrder(5));
+  queue3->Push(FakeTaskWithEnqueueOrder(4));
+  queue4->Push(FakeTaskWithEnqueueOrder(3));
+  size_t set1 = 1;
+  size_t set2 = 2;
+  work_queue_sets_->AssignQueueToSet(queue1, set1);
+  work_queue_sets_->AssignQueueToSet(queue2, set1);
+  work_queue_sets_->AssignQueueToSet(queue3, set2);
+  work_queue_sets_->AssignQueueToSet(queue4, set2);
+
+  WorkQueue* selected_work_queue;
+  EXPECT_TRUE(
+      work_queue_sets_->GetOldestQueueInSet(set1, &selected_work_queue));
+  EXPECT_EQ(queue2, selected_work_queue);
+
+  EXPECT_TRUE(
+      work_queue_sets_->GetOldestQueueInSet(set2, &selected_work_queue));
+  EXPECT_EQ(queue4, selected_work_queue);
+
+  work_queue_sets_->AssignQueueToSet(queue4, set1);
+
+  EXPECT_TRUE(
+      work_queue_sets_->GetOldestQueueInSet(set1, &selected_work_queue));
+  EXPECT_EQ(queue4, selected_work_queue);
+
+  EXPECT_TRUE(
+      work_queue_sets_->GetOldestQueueInSet(set2, &selected_work_queue));
+  EXPECT_EQ(queue3, selected_work_queue);
+}
+
+TEST_F(WorkQueueSetsTest, IsSetEmpty_NoWork) {
+  size_t set = 0;
+  EXPECT_TRUE(work_queue_sets_->IsSetEmpty(set));
+
+  WorkQueue* work_queue = NewTaskQueue("queue");
+  work_queue_sets_->AssignQueueToSet(work_queue, set);
+  EXPECT_TRUE(work_queue_sets_->IsSetEmpty(set));
+}
+
+TEST_F(WorkQueueSetsTest, IsSetEmpty_Work) {
+  size_t set = 0;
+  EXPECT_TRUE(work_queue_sets_->IsSetEmpty(set));
+
+  WorkQueue* work_queue = NewTaskQueue("queue");
+  work_queue->Push(FakeTaskWithEnqueueOrder(1));
+  work_queue_sets_->AssignQueueToSet(work_queue, set);
+  EXPECT_FALSE(work_queue_sets_->IsSetEmpty(set));
+
+  work_queue->PopTaskForTest();
+  work_queue_sets_->OnPopQueue(work_queue);
+  EXPECT_TRUE(work_queue_sets_->IsSetEmpty(set));
+}
+
+}  // namespace internal
+}  // namespace scheduler
diff --git a/components/scheduler/child/idle_helper.cc b/components/scheduler/child/idle_helper.cc
index b0fb06a..9612fb2 100644
--- a/components/scheduler/child/idle_helper.cc
+++ b/components/scheduler/child/idle_helper.cc
@@ -93,7 +93,7 @@
   if (long_idle_period_duration >=
       base::TimeDelta::FromMilliseconds(kMinimumIdlePeriodDurationMillis)) {
     *next_long_idle_period_delay_out = long_idle_period_duration;
-    if (!idle_queue_->HasPendingImmediateTask()) {
+    if (!idle_queue_->HasPendingImmediateWork()) {
       return IdlePeriodState::IN_LONG_IDLE_PERIOD_PAUSED;
     } else if (long_idle_period_duration == max_long_idle_period_duration) {
       return IdlePeriodState::IN_LONG_IDLE_PERIOD_WITH_MAX_DEADLINE;
@@ -175,7 +175,7 @@
 
   TRACE_EVENT0(disabled_by_default_tracing_category_, "StartIdlePeriod");
   idle_queue_->SetQueuePriority(TaskQueue::BEST_EFFORT_PRIORITY);
-  idle_queue_->PumpQueue();
+  idle_queue_->PumpQueue(true);
 
   state_.UpdateState(new_state, idle_period_deadline, now);
 }
@@ -224,13 +224,13 @@
   DCHECK(IsInLongIdlePeriod(state_.idle_period_state()));
   TRACE_EVENT0(disabled_by_default_tracing_category_,
                "UpdateLongIdlePeriodStateAfterIdleTask");
-  TaskQueue::QueueState queue_state = idle_queue_->GetQueueState();
-  if (queue_state == TaskQueue::QueueState::EMPTY) {
+
+  if (!idle_queue_->HasPendingImmediateWork()) {
     // If there are no more idle tasks then pause long idle period ticks until a
     // new idle task is posted.
     state_.UpdateState(IdlePeriodState::IN_LONG_IDLE_PERIOD_PAUSED,
                        state_.idle_period_deadline(), base::TimeTicks());
-  } else if (queue_state == TaskQueue::QueueState::NEEDS_PUMPING) {
+  } else if (idle_queue_->NeedsPumping()) {
     // If there is still idle work to do then just start the next idle period.
     base::TimeDelta next_long_idle_period_delay;
     if (state_.idle_period_state() ==
diff --git a/components/scheduler/child/scheduler_helper_unittest.cc b/components/scheduler/child/scheduler_helper_unittest.cc
index f2d60cf..8f7a649 100644
--- a/components/scheduler/child/scheduler_helper_unittest.cc
+++ b/components/scheduler/child/scheduler_helper_unittest.cc
@@ -176,7 +176,7 @@
 
   EXPECT_CALL(observer, WillProcessTask(_)).Times(0);
   EXPECT_CALL(observer, DidProcessTask(_)).Times(0);
-  scheduler_helper_->ControlAfterWakeUpTaskRunner()->PumpQueue();
+  scheduler_helper_->ControlAfterWakeUpTaskRunner()->PumpQueue(true);
   RunUntilIdle();
 }
 
diff --git a/components/scheduler/child/scheduler_tqm_delegate_for_test.cc b/components/scheduler/child/scheduler_tqm_delegate_for_test.cc
index ddd7a3a..10e910f 100644
--- a/components/scheduler/child/scheduler_tqm_delegate_for_test.cc
+++ b/components/scheduler/child/scheduler_tqm_delegate_for_test.cc
@@ -29,7 +29,7 @@
 
 void SchedulerTqmDelegateForTest::SetDefaultTaskRunner(
     scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
-  default_task_runner_ = task_runner.Pass();
+  default_task_runner_ = std::move(task_runner);
 }
 
 void SchedulerTqmDelegateForTest::RestoreDefaultTaskRunner() {
diff --git a/components/scheduler/child/worker_scheduler.cc b/components/scheduler/child/worker_scheduler.cc
index 18f6cec..c0bd7fd 100644
--- a/components/scheduler/child/worker_scheduler.cc
+++ b/components/scheduler/child/worker_scheduler.cc
@@ -4,6 +4,8 @@
 
 #include "components/scheduler/child/worker_scheduler.h"
 
+#include <utility>
+
 #include "base/message_loop/message_loop.h"
 #include "components/scheduler/child/scheduler_tqm_delegate.h"
 #include "components/scheduler/child/worker_scheduler_impl.h"
@@ -19,7 +21,7 @@
 // static
 scoped_ptr<WorkerScheduler> WorkerScheduler::Create(
     scoped_refptr<SchedulerTqmDelegate> main_task_runner) {
-  return make_scoped_ptr(new WorkerSchedulerImpl(main_task_runner.Pass()));
+  return make_scoped_ptr(new WorkerSchedulerImpl(std::move(main_task_runner)));
 }
 
 }  // namespace scheduler
diff --git a/components/scheduler/renderer/renderer_scheduler_impl.cc b/components/scheduler/renderer/renderer_scheduler_impl.cc
index 0ef81cd..d93b780 100644
--- a/components/scheduler/renderer/renderer_scheduler_impl.cc
+++ b/components/scheduler/renderer/renderer_scheduler_impl.cc
@@ -542,7 +542,7 @@
 
     case UseCase::MAIN_THREAD_GESTURE:
     case UseCase::SYNCHRONIZED_GESTURE:
-      return compositor_task_runner_->HasPendingImmediateTask() ||
+      return compositor_task_runner_->HasPendingImmediateWork() ||
              MainThreadOnly().touchstart_expected_soon;
 
     case UseCase::TOUCHSTART:
diff --git a/components/scheduler/renderer/throttling_helper.cc b/components/scheduler/renderer/throttling_helper.cc
index 88f9ae7..c7525720 100644
--- a/components/scheduler/renderer/throttling_helper.cc
+++ b/components/scheduler/renderer/throttling_helper.cc
@@ -41,7 +41,7 @@
   task_queue->SetTimeDomain(time_domain_.get());
   task_queue->SetPumpPolicy(TaskQueue::PumpPolicy::MANUAL);
 
-  MaybeSchedulePumpThrottledTasksLocked();
+  MaybeSchedulePumpThrottledTasksLocked(FROM_HERE);
 }
 
 void ThrottlingHelper::Unthrottle(TaskQueue* task_queue) {
@@ -59,13 +59,13 @@
   }
   TRACE_EVENT0(tracing_category_,
                "ThrottlingHelper::OnTimeDomainHasImmediateWork");
-  MaybeSchedulePumpThrottledTasksLocked();
+  MaybeSchedulePumpThrottledTasksLocked(FROM_HERE);
 }
 
 void ThrottlingHelper::OnTimeDomainHasDelayedWork() {
   TRACE_EVENT0(tracing_category_,
                "ThrottlingHelper::OnTimeDomainHasDelayedWork");
-  MaybeSchedulePumpThrottledTasksLocked();
+  MaybeSchedulePumpThrottledTasksLocked(FROM_HERE);
 }
 
 void ThrottlingHelper::PumpThrottledTasks() {
@@ -75,15 +75,15 @@
   time_domain_->AdvanceTo(tick_clock_->NowTicks());
   bool work_to_do = false;
   for (TaskQueue* task_queue : throttled_queues_) {
-    if (task_queue->GetQueueState() == TaskQueue::QueueState::EMPTY)
+    if (task_queue->IsEmpty())
       continue;
 
     work_to_do = true;
-    task_queue->PumpQueue();
+    task_queue->PumpQueue(false);
   }
 
   if (work_to_do)
-    MaybeSchedulePumpThrottledTasksLocked();
+    MaybeSchedulePumpThrottledTasksLocked(FROM_HERE);
 }
 
 /* static */
@@ -93,13 +93,14 @@
   return one_second - ((now - base::TimeTicks()) % one_second);
 }
 
-void ThrottlingHelper::MaybeSchedulePumpThrottledTasksLocked() {
+void ThrottlingHelper::MaybeSchedulePumpThrottledTasksLocked(
+    const tracked_objects::Location& from_here) {
   if (pending_pump_throttled_tasks_)
     return;
 
   pending_pump_throttled_tasks_ = true;
   task_runner_->PostDelayedTask(
-      FROM_HERE, pump_throttled_tasks_closure_,
+      from_here, pump_throttled_tasks_closure_,
       DelayToNextRunTimeInSeconds(tick_clock_->NowTicks()));
 }
 
diff --git a/components/scheduler/renderer/throttling_helper.h b/components/scheduler/renderer/throttling_helper.h
index 8417d53..dd4d0fd 100644
--- a/components/scheduler/renderer/throttling_helper.h
+++ b/components/scheduler/renderer/throttling_helper.h
@@ -38,7 +38,8 @@
 
  private:
   void PumpThrottledTasks();
-  void MaybeSchedulePumpThrottledTasksLocked();
+  void MaybeSchedulePumpThrottledTasksLocked(
+      const tracked_objects::Location& from_here);
 
   std::set<TaskQueue*> throttled_queues_;
   base::Closure pump_throttled_tasks_closure_;
diff --git a/components/scheduler/renderer/throttling_helper_unittest.cc b/components/scheduler/renderer/throttling_helper_unittest.cc
index 9526f06..ff82aa3 100644
--- a/components/scheduler/renderer/throttling_helper_unittest.cc
+++ b/components/scheduler/renderer/throttling_helper_unittest.cc
@@ -200,4 +200,30 @@
                           base::TimeDelta::FromMilliseconds(2000.0)));
 }
 
+namespace {
+bool MessageLoopTaskCounter(size_t* count) {
+  *count = *count + 1;
+  return true;
+}
+
+void NopTask() {}
+
+}  // namespace
+
+TEST_F(ThrottlingHelperTest,
+       SingleThrottledTaskPumpedAndRunWithNoExtraneousMessageLoopTasks) {
+  throttling_helper_->Throttle(timer_queue_.get());
+
+  base::TimeDelta delay(base::TimeDelta::FromMilliseconds(10));
+  timer_queue_->PostDelayedTask(FROM_HERE, base::Bind(&NopTask), delay);
+
+  size_t task_count = 0;
+  mock_task_runner_->RunTasksWhile(
+      base::Bind(&MessageLoopTaskCounter, &task_count));
+
+  // NOTE PumpThrottledTasks will always run at least twice because we can only
+  // detect if the queues have become empty before pumping.
+  EXPECT_EQ(2u, task_count);
+}
+
 }  // namespace scheduler
diff --git a/components/scheduler/scheduler.gypi b/components/scheduler/scheduler.gypi
index c6a79b78..21ca898 100644
--- a/components/scheduler/scheduler.gypi
+++ b/components/scheduler/scheduler.gypi
@@ -24,10 +24,12 @@
       'base/task_queue_manager_delegate.h',
       'base/task_queue_selector.cc',
       'base/task_queue_selector.h',
-      'base/task_queue_sets.cc',
-      'base/task_queue_sets.h',
       'base/time_domain.cc',
       'base/time_domain.h',
+      'base/work_queue.cc',
+      'base/work_queue.h',
+      'base/work_queue_sets.cc',
+      'base/work_queue_sets.h',
       'base/pollable_thread_safe_flag.cc',
       'base/pollable_thread_safe_flag.h',
       'base/virtual_time_domain.cc',
diff --git a/components/scheduler/test/lazy_scheduler_message_loop_delegate_for_tests.cc b/components/scheduler/test/lazy_scheduler_message_loop_delegate_for_tests.cc
index ca35441..8c8788a5 100644
--- a/components/scheduler/test/lazy_scheduler_message_loop_delegate_for_tests.cc
+++ b/components/scheduler/test/lazy_scheduler_message_loop_delegate_for_tests.cc
@@ -4,6 +4,8 @@
 
 #include "components/scheduler/test/lazy_scheduler_message_loop_delegate_for_tests.h"
 
+#include <utility>
+
 #include "base/time/default_tick_clock.h"
 
 namespace scheduler {
@@ -37,17 +39,17 @@
   DCHECK(message_loop_);
   original_task_runner_ = message_loop_->task_runner();
   if (pending_task_runner_)
-    message_loop_->SetTaskRunner(pending_task_runner_.Pass());
+    message_loop_->SetTaskRunner(std::move(pending_task_runner_));
   return message_loop_;
 }
 
 void LazySchedulerMessageLoopDelegateForTests::SetDefaultTaskRunner(
     scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
   if (!HasMessageLoop()) {
-    pending_task_runner_ = task_runner.Pass();
+    pending_task_runner_ = std::move(task_runner);
     return;
   }
-  message_loop_->SetTaskRunner(task_runner.Pass());
+  message_loop_->SetTaskRunner(std::move(task_runner));
 }
 
 void LazySchedulerMessageLoopDelegateForTests::RestoreDefaultTaskRunner() {
diff --git a/components/search_engines.gypi b/components/search_engines.gypi
index 64ddbe9..1205392 100644
--- a/components/search_engines.gypi
+++ b/components/search_engines.gypi
@@ -44,8 +44,8 @@
         'search_engines/default_search_policy_handler.h',
         'search_engines/default_search_pref_migration.cc',
         'search_engines/default_search_pref_migration.h',
-        'search_engines/detect_desktop_search_win.cc',
-        'search_engines/detect_desktop_search_win.h',
+        'search_engines/desktop_search_win.cc',
+        'search_engines/desktop_search_win.h',
         'search_engines/keyword_table.cc',
         'search_engines/keyword_table.h',
         'search_engines/keyword_web_data_service.cc',
diff --git a/components/search_engines/BUILD.gn b/components/search_engines/BUILD.gn
index 46fb5e3..e2fa0e4 100644
--- a/components/search_engines/BUILD.gn
+++ b/components/search_engines/BUILD.gn
@@ -11,8 +11,8 @@
     "default_search_manager.h",
     "default_search_pref_migration.cc",
     "default_search_pref_migration.h",
-    "detect_desktop_search_win.cc",
-    "detect_desktop_search_win.h",
+    "desktop_search_win.cc",
+    "desktop_search_win.h",
     "keyword_table.cc",
     "keyword_table.h",
     "keyword_web_data_service.cc",
@@ -114,7 +114,7 @@
   sources = [
     "default_search_manager_unittest.cc",
     "default_search_pref_migration_unittest.cc",
-    "detect_desktop_search_win_unittest.cc",
+    "desktop_search_win_unittest.cc",
     "keyword_table_unittest.cc",
     "search_host_to_urls_map_unittest.cc",
     "template_url_prepopulate_data_unittest.cc",
diff --git a/components/search_engines/detect_desktop_search_win.cc b/components/search_engines/desktop_search_win.cc
similarity index 63%
rename from components/search_engines/detect_desktop_search_win.cc
rename to components/search_engines/desktop_search_win.cc
index 563e80d..b1bae71 100644
--- a/components/search_engines/detect_desktop_search_win.cc
+++ b/components/search_engines/desktop_search_win.cc
@@ -2,17 +2,42 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/search_engines/detect_desktop_search_win.h"
+#include "components/search_engines/desktop_search_win.h"
 
 #include <string>
 
 #include "base/memory/scoped_ptr.h"
+#include "base/prefs/pref_service.h"
 #include "base/strings/string_util.h"
+#include "components/pref_registry/pref_registry_syncable.h"
 #include "components/search_engines/prepopulated_engines.h"
 #include "components/search_engines/template_url.h"
 #include "components/search_engines/template_url_prepopulate_data.h"
 #include "net/base/url_util.h"
 
+namespace prefs {
+const char kWindowsDesktopSearchRedirectionPref[] =
+    "windows_desktop_search_redirection";
+}  // namespace prefs
+
+const base::Feature kWindowsDesktopSearchRedirectionFeature = {
+    "WindowsDesktopSearchRedirection", base::FEATURE_DISABLED_BY_DEFAULT
+};
+
+void RegisterWindowsDesktopSearchRedirectionPref(
+    user_prefs::PrefRegistrySyncable* registry) {
+  registry->RegisterBooleanPref(prefs::kWindowsDesktopSearchRedirectionPref,
+                                false);
+}
+
+bool ShouldRedirectWindowsDesktopSearchToDefaultSearchEngine(
+    PrefService* pref_service) {
+  DCHECK(pref_service);
+  return base::FeatureList::IsEnabled(
+             kWindowsDesktopSearchRedirectionFeature) &&
+         pref_service->GetBoolean(prefs::kWindowsDesktopSearchRedirectionPref);
+}
+
 bool DetectWindowsDesktopSearch(const GURL& url,
                                 const SearchTermsData& search_terms_data,
                                 base::string16* search_terms) {
@@ -37,7 +62,7 @@
     // Use a case-insensitive comparison because the key is sometimes in capital
     // letters.
     if (base::EqualsCaseInsensitiveASCII(it.GetKey(), kBingSourceQueryKey)) {
-      std::string source = it.GetValue();
+      const std::string source = it.GetValue();
       if (source == kBingSourceDesktopText || source == kBingSourceDesktopVoice)
         return true;
     }
diff --git a/components/search_engines/desktop_search_win.h b/components/search_engines/desktop_search_win.h
new file mode 100644
index 0000000..162e95f2
--- /dev/null
+++ b/components/search_engines/desktop_search_win.h
@@ -0,0 +1,44 @@
+// 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.
+
+#ifndef COMPONENTS_SEARCH_ENGINES_DESKTOP_SEARCH_WIN_H_
+#define COMPONENTS_SEARCH_ENGINES_DESKTOP_SEARCH_WIN_H_
+
+#include "base/feature_list.h"
+#include "base/strings/string16.h"
+
+class GURL;
+class PrefService;
+class SearchTermsData;
+
+namespace user_prefs {
+class PrefRegistrySyncable;
+}
+
+namespace prefs {
+// Name of the Windows desktop search redirection preference.
+extern const char kWindowsDesktopSearchRedirectionPref[];
+}
+
+// Windows desktop search redirection feature. This is exposed in the header
+// file so that it can be referenced from about_flags.cc.
+extern const base::Feature kWindowsDesktopSearchRedirectionFeature;
+
+// Registers the Windows desktop search redirection preference into |registry|.
+void RegisterWindowsDesktopSearchRedirectionPref(
+    user_prefs::PrefRegistrySyncable* registry);
+
+// Indicates whether Windows desktop searches should be redirected to the
+// default search engine. This is only true when both the preference and the
+// feature are enabled. The preference value is read from |pref_service|.
+bool ShouldRedirectWindowsDesktopSearchToDefaultSearchEngine(
+    PrefService* pref_service);
+
+// Detects whether a URL comes from a Windows Desktop search. If so, puts the
+// search terms in |search_terms| and returns true.
+bool DetectWindowsDesktopSearch(const GURL& url,
+                                const SearchTermsData& search_terms_data,
+                                base::string16* search_terms);
+
+#endif  // COMPONENTS_SEARCH_ENGINES_DESKTOP_SEARCH_WIN_H_
diff --git a/components/search_engines/desktop_search_win_unittest.cc b/components/search_engines/desktop_search_win_unittest.cc
new file mode 100644
index 0000000..a49e3ef1
--- /dev/null
+++ b/components/search_engines/desktop_search_win_unittest.cc
@@ -0,0 +1,45 @@
+// 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.
+
+#include "components/search_engines/desktop_search_win.h"
+
+#include "base/macros.h"
+#include "base/strings/string16.h"
+#include "components/search_engines/testing_search_terms_data.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+namespace {
+struct DetectWindowsDesktopSearchTestData {
+  const char* url;
+  const wchar_t* expected_search_terms;
+};
+}  // namespace
+
+TEST(WindowsDesktopSearch, DetectWindowsDesktopSearch) {
+  const DetectWindowsDesktopSearchTestData test_data[] = {
+      {"https://www.google.com", L""},
+      {"https://www.bing.com/search", L""},
+      {"https://www.bing.com/search?q=keyword&form=QBLH", L""},
+      {"https://www.bing.com/search?q=keyword&form=WNSGPH", L"keyword"},
+      {"https://www.bing.com/search?q=keyword&form=WNSBOX", L"keyword"},
+      {"https://www.bing.com/search?q=keyword&FORM=WNSGPH", L"keyword"},
+      {"https://www.bing.com/search?q=keyword&FORM=WNSBOX", L"keyword"},
+      {"https://www.bing.com/search?form=WNSGPH&q=keyword", L"keyword"},
+      {"https://www.bing.com/search?q=keyword&form=WNSGPH&other=stuff",
+       L"keyword"},
+      {"https://www.bing.com/search?q=%C3%A8+%C3%A9&form=WNSGPH", L"\xE8 \xE9"},
+  };
+
+  for (size_t i = 0; i < arraysize(test_data); ++i) {
+    TestingSearchTermsData search_terms_data("https://www.google.com");
+    base::string16 search_terms;
+    bool is_desktop_search = DetectWindowsDesktopSearch(
+        GURL(test_data[i].url), search_terms_data, &search_terms);
+    const base::string16 expected_search_terms(
+        test_data[i].expected_search_terms);
+    EXPECT_EQ(!expected_search_terms.empty(), is_desktop_search);
+    EXPECT_EQ(expected_search_terms, search_terms);
+  }
+}
diff --git a/components/search_engines/detect_desktop_search_win.h b/components/search_engines/detect_desktop_search_win.h
deleted file mode 100644
index 3d648a62..0000000
--- a/components/search_engines/detect_desktop_search_win.h
+++ /dev/null
@@ -1,19 +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.
-
-#ifndef COMPONENTS_SEARCH_ENGINES_DETECT_DESKTOP_SEARCH_WIN_H_
-#define COMPONENTS_SEARCH_ENGINES_DETECT_DESKTOP_SEARCH_WIN_H_
-
-#include "base/strings/string16.h"
-
-class GURL;
-class SearchTermsData;
-
-// Detects whether a URL comes from a Windows Desktop search. If so, puts the
-// search terms in |search_terms| and returns true.
-bool DetectWindowsDesktopSearch(const GURL& url,
-                                const SearchTermsData& search_terms_data,
-                                base::string16* search_terms);
-
-#endif  // COMPONENTS_SEARCH_ENGINES_DETECT_DESKTOP_SEARCH_WIN_H_
diff --git a/components/search_engines/search_engines_switches.cc b/components/search_engines/search_engines_switches.cc
index f15afa7a..190662c 100644
--- a/components/search_engines/search_engines_switches.cc
+++ b/components/search_engines/search_engines_switches.cc
@@ -10,10 +10,4 @@
 // testing.
 const char kExtraSearchQueryParams[] = "extra-search-query-params";
 
-#if defined(OS_WIN)
-// Use the default search provider for desktop search.
-const char kUseDefaultSearchProviderForDesktopSearch[] =
-    "use-default-search-provider-for-desktop-search";
-#endif  // defined(OS_WIN)
-
 }  // namespace switches
diff --git a/components/search_engines/search_engines_switches.h b/components/search_engines/search_engines_switches.h
index fc3ab109..476280c 100644
--- a/components/search_engines/search_engines_switches.h
+++ b/components/search_engines/search_engines_switches.h
@@ -11,10 +11,6 @@
 
 extern const char kExtraSearchQueryParams[];
 
-#if defined(OS_WIN)
-extern const char kUseDefaultSearchProviderForDesktopSearch[];
-#endif  // defined(OS_WIN)
-
 }  // namespace switches
 
 #endif  // COMPONENTS_SEARCH_ENGINES_SEARCH_ENGINES_SWITCHES_H_
diff --git a/components/security_interstitials/core/browser/resources/interstitial_v2.js b/components/security_interstitials/core/browser/resources/interstitial_v2.js
index e29ae8e..43e76833 100644
--- a/components/security_interstitials/core/browser/resources/interstitial_v2.js
+++ b/components/security_interstitials/core/browser/resources/interstitial_v2.js
@@ -31,8 +31,17 @@
  * @param {string} cmd  The command to send.
  */
 function sendCommand(cmd) {
+<if expr="not is_ios">
   window.domAutomationController.setAutomationId(1);
   window.domAutomationController.send(cmd);
+</if>
+<if expr="is_ios">
+  // TODO(crbug.com/565877): Revisit message passing for WKWebView.
+  var iframe = document.createElement('IFRAME');
+  iframe.setAttribute('src', 'js-command:' + cmd);
+  document.documentElement.appendChild(iframe);
+  iframe.parentNode.removeChild(iframe);
+</if>
 }
 
 /**
diff --git a/components/sync_bookmarks/bookmark_change_processor.cc b/components/sync_bookmarks/bookmark_change_processor.cc
index 0f1a79d3..df65f78e 100644
--- a/components/sync_bookmarks/bookmark_change_processor.cc
+++ b/components/sync_bookmarks/bookmark_change_processor.cc
@@ -100,8 +100,8 @@
   const gfx::Image& favicon = model->GetFavicon(src);
 
   // Check for empty images.  This can happen if the favicon is
-  // still being loaded.
-  if (favicon.IsEmpty())
+  // still being loaded.  Also avoid syncing touch icons.
+  if (favicon.IsEmpty() || model->GetFaviconType(src) != favicon_base::FAVICON)
     return;
 
   // Re-encode the BookmarkNode's favicon as a PNG, and pass the data to the
diff --git a/components/sync_driver/non_blocking_data_type_controller_unittest.cc b/components/sync_driver/non_blocking_data_type_controller_unittest.cc
index 0c857fd..9d92f44 100644
--- a/components/sync_driver/non_blocking_data_type_controller_unittest.cc
+++ b/components/sync_driver/non_blocking_data_type_controller_unittest.cc
@@ -19,6 +19,7 @@
 #include "sync/engine/commit_queue.h"
 #include "sync/internal_api/public/activation_context.h"
 #include "sync/internal_api/public/shared_model_type_processor.h"
+#include "sync/internal_api/public/test/fake_model_type_service.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace sync_driver_v2 {
@@ -187,9 +188,9 @@
 
  protected:
   void CreateTypeProcessor() {
-    // TODO(pavely): stop passing ModelTypeStore.
-    type_processor_.reset(new syncer_v2::SharedModelTypeProcessor(
-        syncer::DICTIONARY, base::WeakPtr<syncer_v2::ModelTypeStore>()));
+    // TODO(stanisc): Controller should discover the service via SyncClient.
+    type_processor_.reset(
+        new syncer_v2::SharedModelTypeProcessor(syncer::DICTIONARY, &service_));
     type_processor_for_ui_ = type_processor_->AsWeakPtrForUI();
   }
 
@@ -330,6 +331,7 @@
   scoped_refptr<base::TestSimpleTaskRunner> sync_thread_runner_;
   MockSyncBackend backend_;
   MockBackendDataTypeConfigurer configurer_;
+  syncer_v2::FakeModelTypeService service_;
 };
 
 TEST_F(NonBlockingDataTypeControllerTest, InitialState) {
diff --git a/components/test/data/arc/icon_100p.png b/components/test/data/arc/icon_100p.png
new file mode 100644
index 0000000..80a5d686
--- /dev/null
+++ b/components/test/data/arc/icon_100p.png
Binary files differ
diff --git a/components/test/data/arc/icon_125p.png b/components/test/data/arc/icon_125p.png
new file mode 100644
index 0000000..c9bae8e
--- /dev/null
+++ b/components/test/data/arc/icon_125p.png
Binary files differ
diff --git a/components/test/data/arc/icon_133p.png b/components/test/data/arc/icon_133p.png
new file mode 100644
index 0000000..565bbac
--- /dev/null
+++ b/components/test/data/arc/icon_133p.png
Binary files differ
diff --git a/components/test/data/arc/icon_140p.png b/components/test/data/arc/icon_140p.png
new file mode 100644
index 0000000..f85cae5a
--- /dev/null
+++ b/components/test/data/arc/icon_140p.png
Binary files differ
diff --git a/components/test/data/arc/icon_150p.png b/components/test/data/arc/icon_150p.png
new file mode 100644
index 0000000..e3471fd
--- /dev/null
+++ b/components/test/data/arc/icon_150p.png
Binary files differ
diff --git a/components/test/data/arc/icon_180p.png b/components/test/data/arc/icon_180p.png
new file mode 100644
index 0000000..91c8dcb
--- /dev/null
+++ b/components/test/data/arc/icon_180p.png
Binary files differ
diff --git a/components/test/data/arc/icon_200p.png b/components/test/data/arc/icon_200p.png
new file mode 100644
index 0000000..be3aa10
--- /dev/null
+++ b/components/test/data/arc/icon_200p.png
Binary files differ
diff --git a/components/test/data/arc/icon_250p.png b/components/test/data/arc/icon_250p.png
new file mode 100644
index 0000000..4843664
--- /dev/null
+++ b/components/test/data/arc/icon_250p.png
Binary files differ
diff --git a/components/test/data/arc/icon_300p.png b/components/test/data/arc/icon_300p.png
new file mode 100644
index 0000000..d0afd969
--- /dev/null
+++ b/components/test/data/arc/icon_300p.png
Binary files differ
diff --git a/components/test_runner/mock_webrtc_peer_connection_handler.cc b/components/test_runner/mock_webrtc_peer_connection_handler.cc
index 3aaa91d..1fb0bc9 100644
--- a/components/test_runner/mock_webrtc_peer_connection_handler.cc
+++ b/components/test_runner/mock_webrtc_peer_connection_handler.cc
@@ -9,11 +9,11 @@
 #include "components/test_runner/mock_webrtc_dtmf_sender_handler.h"
 #include "components/test_runner/test_interfaces.h"
 #include "components/test_runner/web_test_delegate.h"
-#include "third_party/WebKit/public/platform/WebMediaConstraints.h"
 #include "third_party/WebKit/public/platform/WebMediaStream.h"
 #include "third_party/WebKit/public/platform/WebMediaStreamSource.h"
 #include "third_party/WebKit/public/platform/WebMediaStreamTrack.h"
 #include "third_party/WebKit/public/platform/WebRTCDataChannelInit.h"
+#include "third_party/WebKit/public/platform/WebRTCOfferOptions.h"
 #include "third_party/WebKit/public/platform/WebRTCPeerConnectionHandlerClient.h"
 #include "third_party/WebKit/public/platform/WebRTCStatsResponse.h"
 #include "third_party/WebKit/public/platform/WebRTCVoidRequest.h"
@@ -178,24 +178,24 @@
 void MockWebRTCPeerConnectionHandler::createOffer(
     const WebRTCSessionDescriptionRequest& request,
     const WebMediaConstraints& constraints) {
-  WebString should_succeed;
-  if (constraints.getMandatoryConstraintValue("succeed", should_succeed) &&
-      should_succeed == "true") {
-    WebRTCSessionDescription session_description;
-    session_description.initialize("offer", "local");
-    interfaces_->GetDelegate()->PostTask(
-        new RTCSessionDescriptionRequestSuccededTask(
-            this, request, session_description));
-  } else
-    interfaces_->GetDelegate()->PostTask(
-        new RTCSessionDescriptionRequestFailedTask(this, request));
+  interfaces_->GetDelegate()->PostTask(
+      new RTCSessionDescriptionRequestFailedTask(this, request));
 }
 
 void MockWebRTCPeerConnectionHandler::createOffer(
     const WebRTCSessionDescriptionRequest& request,
     const blink::WebRTCOfferOptions& options) {
-  interfaces_->GetDelegate()->PostTask(
-      new RTCSessionDescriptionRequestFailedTask(this, request));
+  WebString should_succeed;
+  if (options.iceRestart() && options.voiceActivityDetection()) {
+    WebRTCSessionDescription session_description;
+    session_description.initialize("offer", "local");
+    interfaces_->GetDelegate()->PostTask(
+        new RTCSessionDescriptionRequestSuccededTask(
+            this, request, session_description));
+  } else {
+    interfaces_->GetDelegate()->PostTask(
+        new RTCSessionDescriptionRequestFailedTask(this, request));
+  }
 }
 
 void MockWebRTCPeerConnectionHandler::createAnswer(
diff --git a/components/test_runner/test_plugin.h b/components/test_runner/test_plugin.h
index 129dc2a..6c52dfe8 100644
--- a/components/test_runner/test_plugin.h
+++ b/components/test_runner/test_plugin.h
@@ -85,11 +85,6 @@
   void didReceiveData(const char* data, int data_length) override {}
   void didFinishLoading() override {}
   void didFailLoading(const blink::WebURLError& error) override {}
-  void didFinishLoadingFrameRequest(const blink::WebURL& url,
-                                    void* notify_data) override {}
-  void didFailLoadingFrameRequest(const blink::WebURL& url,
-                                  void* notify_data,
-                                  const blink::WebURLError& error) override {}
   bool isPlaceholder() override;
 
   // cc::TextureLayerClient methods:
diff --git a/components/variations/variations_request_scheduler.cc b/components/variations/variations_request_scheduler.cc
index 9c239afa..4834421 100644
--- a/components/variations/variations_request_scheduler.cc
+++ b/components/variations/variations_request_scheduler.cc
@@ -50,8 +50,8 @@
   if (base::StringToSizeT(period_min_str, &period_min))
     return base::TimeDelta::FromMinutes(period_min);
 
-  // The default fetch interval is every 5 hours.
-  return base::TimeDelta::FromHours(5);
+  // The default fetch interval is every 30 minutes.
+  return base::TimeDelta::FromMinutes(30);
 }
 
 base::Closure VariationsRequestScheduler::task() const {
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index 9501557..ff1b66d 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -110,6 +110,7 @@
     sources += [
       "mojo/mojo_shell_client_host.cc",
       "mojo/mojo_shell_client_host.h",
+      "mojo/renderer_capability_filter.cc",
     ]
 
     # Non-iOS deps.
diff --git a/content/browser/accessibility/android_granularity_movement_browsertest.cc b/content/browser/accessibility/android_granularity_movement_browsertest.cc
index 74a67a4..6ddf830 100644
--- a/content/browser/accessibility/android_granularity_movement_browsertest.cc
+++ b/content/browser/accessibility/android_granularity_movement_browsertest.cc
@@ -204,7 +204,7 @@
   BrowserAccessibility* pre = root->PlatformGetChild(0);
   ASSERT_EQ(0U, pre->PlatformChildCount());
 
-  ASSERT_EQ(base::ASCIIToUTF16("'One, ', 'two, ', 'three!'"),
+  ASSERT_EQ(base::ASCIIToUTF16("'One,', 'two,', 'three!'"),
             TraverseNodeAtGranularity(pre, GRANULARITY_LINE));
 }
 
diff --git a/content/browser/accessibility/browser_accessibility.cc b/content/browser/accessibility/browser_accessibility.cc
index 196656c..a057213d 100644
--- a/content/browser/accessibility/browser_accessibility.cc
+++ b/content/browser/accessibility/browser_accessibility.cc
@@ -41,15 +41,25 @@
   if (InternalChildCount() == 0)
     return true;
 
-  // All of these roles may have children that we use as internal
-  // implementation details, but we want to expose them as leaves
-  // to platform accessibility APIs.
+  // These types of objects may have children that we use as internal
+  // implementation details, but we want to expose them as leaves to platform
+  // accessibility APIs because screen readers might be confused if they find
+  // any children.
+  if (IsSimpleTextControl() || IsTextOnlyObject())
+    return true;
+
+  // Roles whose children are only presentational according to the ARIA and
+  // HTML5 Specs.
+  // (Note that whilst ARIA buttons can have only presentational children, HTML5
+  // buttons are allowed to have content.)
   switch (GetRole()) {
-    case ui::AX_ROLE_COMBO_BOX:
-    case ui::AX_ROLE_LINE_BREAK:
+    case ui::AX_ROLE_IMAGE:
+    case ui::AX_ROLE_MATH:
+    case ui::AX_ROLE_METER:
+    case ui::AX_ROLE_SCROLL_BAR:
     case ui::AX_ROLE_SLIDER:
-    case ui::AX_ROLE_STATIC_TEXT:
-    case ui::AX_ROLE_TEXT_FIELD:
+    case ui::AX_ROLE_SPLITTER:
+    case ui::AX_ROLE_PROGRESS_INDICATOR:
       return true;
     default:
       return false;
@@ -712,7 +722,7 @@
   }
 }
 
-bool BrowserAccessibility::IsTextControl() const {
+bool BrowserAccessibility::IsSimpleTextControl() const {
   // Time fields, color wells and spinner buttons might also use text fields as
   // constituent parts, but they are not considered text fields as a whole.
   switch (GetRole()) {
@@ -725,6 +735,12 @@
   }
 }
 
+// Indicates if this object is at the root of a rich edit text control.
+bool BrowserAccessibility::IsRichTextControl() const {
+  return HasState(ui::AX_STATE_RICHLY_EDITABLE) &&
+         (!GetParent() || !GetParent()->HasState(ui::AX_STATE_RICHLY_EDITABLE));
+}
+
 std::string BrowserAccessibility::ComputeAccessibleNameFromDescendants() {
   std::string name;
   for (size_t i = 0; i < InternalChildCount(); ++i) {
diff --git a/content/browser/accessibility/browser_accessibility.h b/content/browser/accessibility/browser_accessibility.h
index a516b5f..e5e5927 100644
--- a/content/browser/accessibility/browser_accessibility.h
+++ b/content/browser/accessibility/browser_accessibility.h
@@ -296,7 +296,9 @@
   bool IsWebAreaForPresentationalIframe() const;
 
   bool IsControl() const;
-  bool IsTextControl() const;
+  bool IsSimpleTextControl() const;
+  // Indicates if this object is at the root of a rich edit text control.
+  bool IsRichTextControl() const;
 
   // If an object is focusable but has no accessible name, use this
   // to compute a name from its descendants.
diff --git a/content/browser/accessibility/browser_accessibility_cocoa.h b/content/browser/accessibility/browser_accessibility_cocoa.h
index fbebd859..6c5a3e6 100644
--- a/content/browser/accessibility/browser_accessibility_cocoa.h
+++ b/content/browser/accessibility/browser_accessibility_cocoa.h
@@ -61,10 +61,6 @@
 // Returns the requested text range from this object's value attribute.
 - (NSString*)valueForRange:(NSRange)range;
 
-// Indicates if this object is at the root of a rich edit text field.
-@property(nonatomic, readonly, getter=isRichEditTextField)
-    BOOL richEditTextField;
-
 // Internally-used method.
 @property(nonatomic, readonly) NSPoint origin;
 
diff --git a/content/browser/accessibility/browser_accessibility_cocoa.mm b/content/browser/accessibility/browser_accessibility_cocoa.mm
index bf183096..20a3621 100644
--- a/content/browser/accessibility/browser_accessibility_cocoa.mm
+++ b/content/browser/accessibility/browser_accessibility_cocoa.mm
@@ -228,7 +228,7 @@
     };
   } else if ([searchKey isEqualToString:@"AXTextFieldSearchKey"]) {
     return [](BrowserAccessibility* start, BrowserAccessibility* current) {
-      return current->GetRole() == ui::AX_ROLE_TEXT_FIELD;
+      return current->IsSimpleTextControl() || current->IsRichTextControl();
     };
   } else if ([searchKey isEqualToString:@"AXUnderlineSearchKey"]) {
     // TODO(dmazzoni): implement this.
@@ -928,6 +928,9 @@
 
 // Returns a string indicating the NSAccessibility role of this object.
 - (NSString*)role {
+  if (!browserAccessibility_)
+    return nil;
+
   ui::AXRole role = [self internalRole];
   if (role == ui::AX_ROLE_CANVAS &&
       browserAccessibility_->GetBoolAttribute(
@@ -945,9 +948,9 @@
     else
       return NSAccessibilityButtonRole;
   }
-  if ((role == ui::AX_ROLE_TEXT_FIELD &&
+  if ((browserAccessibility_->IsSimpleTextControl() &&
        browserAccessibility_->HasState(ui::AX_STATE_MULTILINE)) ||
-      [self isRichEditTextField]) {
+      browserAccessibility_->IsRichTextControl()) {
     return NSAccessibilityTextAreaRole;
   }
 
@@ -1433,21 +1436,6 @@
   children_.swap(*other);
 }
 
-// Indicates if this object is at the root of a rich edit text field.
-- (BOOL)isRichEditTextField {
-  if (!browserAccessibility_)
-    return NO;
-
-  if (browserAccessibility_->HasState(ui::AX_STATE_RICHLY_EDITABLE) &&
-      !(browserAccessibility_->GetParent() &&
-        browserAccessibility_->GetParent()->HasState(
-            ui::AX_STATE_RICHLY_EDITABLE))) {
-    return YES;
-  }
-
-  return NO;
-}
-
 // Returns the requested text range from this object's value attribute.
 - (NSString*)valueForRange:(NSRange)range {
   if (!browserAccessibility_)
diff --git a/content/browser/accessibility/browser_accessibility_win.cc b/content/browser/accessibility/browser_accessibility_win.cc
index 99821b8..3009bfa 100644
--- a/content/browser/accessibility/browser_accessibility_win.cc
+++ b/content/browser/accessibility/browser_accessibility_win.cc
@@ -3421,8 +3421,8 @@
 }
 
 void BrowserAccessibilityWin::UpdateStep2ComputeHypertext() {
-  if (!PlatformChildCount()) {
-    if (IsTextControl())
+  if (PlatformIsLeaf()) {
+    if (IsSimpleTextControl())
       win_attributes_->hypertext += value();
     else
       win_attributes_->hypertext += name();
@@ -3702,14 +3702,18 @@
   DCHECK(child.GetParent() == this);
 
   // Handle the case when we are dealing with a direct text-only child.
+  // (Note that this object might be a platform leaf, e.g. an ARIA searchbox,
+  // and so InternalChild... functions need to be used. Also, direct text-only
+  // children should not be present at tree roots and so no cross-tree traversal
+  // is necessary.)
   if (child.IsTextOnlyObject()) {
     int32 hypertextOffset = 0;
     int32 index_in_parent = child.GetIndexInParent();
     DCHECK_GE(index_in_parent, 0);
-    DCHECK_LT(index_in_parent, static_cast<int32>(PlatformChildCount()));
+    DCHECK_LT(index_in_parent, static_cast<int32>(InternalChildCount()));
     for (uint32 i = 0; i < static_cast<uint32>(index_in_parent); ++i) {
       const BrowserAccessibilityWin* sibling =
-          PlatformGetChild(i)->ToBrowserAccessibilityWin();
+          InternalGetChild(i)->ToBrowserAccessibilityWin();
       DCHECK(sibling);
       if (sibling->IsTextOnlyObject())
         hypertextOffset += sibling->hypertext().length();
@@ -3791,8 +3795,8 @@
   // We can safely assume that the endpoint is in another part of the tree or
   // at common parent, and that this object is a descendant of common parent.
   int32 endpoint_index_in_common_parent = -1;
-  for (uint32 i = 0; i < common_parent->PlatformChildCount(); ++i) {
-    const BrowserAccessibility* child = common_parent->PlatformGetChild(i);
+  for (uint32 i = 0; i < common_parent->InternalChildCount(); ++i) {
+    const BrowserAccessibility* child = common_parent->InternalGetChild(i);
     DCHECK(child);
     if (endpoint_object.IsDescendantOf(child)) {
       endpoint_index_in_common_parent = child->GetIndexInParent();
@@ -3812,19 +3816,19 @@
 
 int BrowserAccessibilityWin::GetSelectionAnchor() const {
   int32 anchor_id = manager()->GetTreeData().sel_anchor_object_id;
-  BrowserAccessibilityWin* anchor_object = manager()->GetFromID(
-      anchor_id)->ToBrowserAccessibilityWin();
+  const auto anchor_object =
+      manager()->GetFromID(anchor_id)->ToBrowserAccessibilityWin();
   if (!anchor_object)
     return -1;
 
-  int32 anchor_offset = manager()->GetTreeData().sel_anchor_offset;
+  int anchor_offset = manager()->GetTreeData().sel_anchor_offset;
   return GetHypertextOffsetFromEndpoint(*anchor_object, anchor_offset);
 }
 
 int BrowserAccessibilityWin::GetSelectionFocus() const {
   int32 focus_id = manager()->GetTreeData().sel_focus_object_id;
-  BrowserAccessibilityWin* focus_object = manager()->GetFromID(
-      focus_id)->ToBrowserAccessibilityWin();
+  const auto focus_object =
+      manager()->GetFromID(focus_id)->ToBrowserAccessibilityWin();
   if (!focus_object)
     return -1;
 
@@ -4023,10 +4027,8 @@
     LONG start_offset,
     ui::TextBoundaryDirection direction) {
   HandleSpecialTextOffset(text, &start_offset);
-  if (ia2_boundary == IA2_TEXT_BOUNDARY_WORD &&
-      GetRole() == ui::AX_ROLE_TEXT_FIELD) {
+  if (ia2_boundary == IA2_TEXT_BOUNDARY_WORD && IsSimpleTextControl())
     return GetWordStartBoundary(static_cast<int>(start_offset), direction);
-  }
 
   ui::TextBoundaryType boundary = IA2TextBoundaryToTextBoundary(ia2_boundary);
   const std::vector<int32>& line_breaks = GetIntListAttribute(
@@ -4115,7 +4117,7 @@
   // Expose input-text type attribute.
   base::string16 type;
   base::string16 html_tag = GetString16Attribute(ui::AX_ATTR_HTML_TAG);
-  if (GetRole() == ui::AX_ROLE_TEXT_FIELD && html_tag == L"input" &&
+  if (IsSimpleTextControl() && html_tag == L"input" &&
       GetHtmlAttribute("type", &type)) {
     SanitizeStringAttributeForIA2(type, &type);
     win_attributes_->ia2_attributes.push_back(L"text-input-type:" + type);
diff --git a/content/browser/accessibility/dump_accessibility_events_browsertest.cc b/content/browser/accessibility/dump_accessibility_events_browsertest.cc
index 304fc071..3bd1fd7 100644
--- a/content/browser/accessibility/dump_accessibility_events_browsertest.cc
+++ b/content/browser/accessibility/dump_accessibility_events_browsertest.cc
@@ -213,8 +213,11 @@
 #if defined(OS_WIN)
 #define MAYBE_AccessibilityEventsListboxNext \
   DISABLED_AccessibilityEventsListboxNext
+#define MAYBE_AccessibilityEventsMenuListPopup \
+  DISABLED_AccessibilityEventsMenuListPopup
 #else
 #define MAYBE_AccessibilityEventsListboxNext AccessibilityEventsListboxNext
+#define MAYBE_AccessibilityEventsMenuListPopup AccessibilityEventsMenuListPopup
 #endif
 
 IN_PROC_BROWSER_TEST_F(DumpAccessibilityEventsTest,
@@ -233,7 +236,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(DumpAccessibilityEventsTest,
-                       AccessibilityEventsMenuListPopup) {
+                       MAYBE_AccessibilityEventsMenuListPopup) {
   RunEventTest(FILE_PATH_LITERAL("menulist-popup.html"));
 }
 
diff --git a/content/browser/android/content_view_core_impl.cc b/content/browser/android/content_view_core_impl.cc
index 0c3a6ae1..61296db 100644
--- a/content/browser/android/content_view_core_impl.cc
+++ b/content/browser/android/content_view_core_impl.cc
@@ -610,18 +610,18 @@
       selection_rect_pix.right(), selection_rect_pix.bottom());
 }
 
-void ContentViewCoreImpl::ShowPastePopup(int x_dip, int y_dip) {
+bool ContentViewCoreImpl::ShowPastePopup(int x_dip, int y_dip) {
   RenderWidgetHostViewAndroid* view = GetRenderWidgetHostViewAndroid();
   if (!view)
-    return;
+    return false;
 
   view->OnShowingPastePopup(gfx::PointF(x_dip, y_dip));
 
   JNIEnv* env = AttachCurrentThread();
   ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
   if (obj.is_null())
-    return;
-  Java_ContentViewCore_showPastePopupWithFeedback(
+    return false;
+  return Java_ContentViewCore_showPastePopupWithFeedback(
       env, obj.obj(), static_cast<jint>(x_dip * dpi_scale()),
       static_cast<jint>(y_dip * dpi_scale()));
 }
diff --git a/content/browser/android/content_view_core_impl.h b/content/browser/android/content_view_core_impl.h
index c3acf0b..10444f75 100644
--- a/content/browser/android/content_view_core_impl.h
+++ b/content/browser/android/content_view_core_impl.h
@@ -53,7 +53,7 @@
   ui::ViewAndroid* GetViewAndroid() const override;
   ui::WindowAndroid* GetWindowAndroid() const override;
   const scoped_refptr<cc::Layer>& GetLayer() const override;
-  void ShowPastePopup(int x, int y) override;
+  bool ShowPastePopup(int x, int y) override;
   void GetScaledContentBitmap(
       float scale,
       SkColorType preferred_color_type,
diff --git a/content/browser/bad_message.h b/content/browser/bad_message.h
index 31f166c..356eb0e2 100644
--- a/content/browser/bad_message.h
+++ b/content/browser/bad_message.h
@@ -123,6 +123,7 @@
   RFH_OWNER_PROPERTY = 99,
   BDH_EMPTY_OR_INVALID_FILTERS = 100,
   WC_CONTENT_WITH_CERT_ERRORS_BAD_SECURITY_INFO = 101,
+  RFMF_RENDERER_FAKED_ITS_OWN_DEATH = 102,
 
   // Please add new elements here. The naming convention is abbreviated class
   // name (e.g. RenderFrameHost becomes RFH) plus a unique description of the
diff --git a/content/browser/bluetooth/bluetooth_dispatcher_host.cc b/content/browser/bluetooth/bluetooth_dispatcher_host.cc
index 898a7283..7758a3e 100644
--- a/content/browser/bluetooth/bluetooth_dispatcher_host.cc
+++ b/content/browser/bluetooth/bluetooth_dispatcher_host.cc
@@ -11,6 +11,8 @@
 
 #include "content/browser/bluetooth/bluetooth_dispatcher_host.h"
 
+#include <utility>
+
 #include "base/bind.h"
 #include "base/single_thread_task_runner.h"
 #include "base/strings/utf_string_conversions.h"
@@ -297,7 +299,7 @@
     devices_with_discovered_services_.clear();
   }
 
-  set_adapter(mock_adapter.Pass());
+  set_adapter(std::move(mock_adapter));
 }
 
 BluetoothDispatcherHost::~BluetoothDispatcherHost() {
diff --git a/content/browser/browser_context.cc b/content/browser/browser_context.cc
index be99f673..d516cd48 100644
--- a/content/browser/browser_context.cc
+++ b/content/browser/browser_context.cc
@@ -122,8 +122,6 @@
     BrowserContext* context) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   if (!context->GetUserData(kDownloadManagerKeyName)) {
-    ResourceDispatcherHostImpl* rdh = ResourceDispatcherHostImpl::Get();
-    DCHECK(rdh);
     DownloadManager* download_manager =
         new DownloadManagerImpl(
             GetContentClient()->browser()->GetNetLog(), context);
diff --git a/content/browser/devtools/site_per_process_devtools_browsertest.cc b/content/browser/devtools/site_per_process_devtools_browsertest.cc
index 661ab8f..489cd50 100644
--- a/content/browser/devtools/site_per_process_devtools_browsertest.cc
+++ b/content/browser/devtools/site_per_process_devtools_browsertest.cc
@@ -109,8 +109,7 @@
 
 IN_PROC_BROWSER_TEST_F(SitePerProcessDevToolsBrowserTest, AgentHostForFrames) {
   host_resolver()->AddRule("*", "127.0.0.1");
-  ASSERT_TRUE(test_server()->Start());
-  GURL main_url(test_server()->GetURL("files/site_per_process_main.html"));
+  GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
   NavigateToURL(shell(), main_url);
 
   scoped_refptr<DevToolsAgentHost> page_agent =
@@ -127,7 +126,7 @@
 
   // Load same-site page into iframe.
   FrameTreeNode* child = root->child_at(0);
-  GURL http_url(test_server()->GetURL("files/title1.html"));
+  GURL http_url(embedded_test_server()->GetURL("/title1.html"));
   NavigateFrameToURL(child, http_url);
 
   scoped_refptr<DevToolsAgentHost> child_frame_agent =
@@ -136,7 +135,7 @@
 
   // Load cross-site page into iframe.
   GURL::Replacements replace_host;
-  GURL cross_site_url(test_server()->GetURL("files/title2.html"));
+  GURL cross_site_url(embedded_test_server()->GetURL("/title2.html"));
   replace_host.SetHostStr("foo.com");
   cross_site_url = cross_site_url.ReplaceComponents(replace_host);
   NavigateFrameToURL(root->child_at(0), cross_site_url);
diff --git a/content/browser/download/download_browsertest.cc b/content/browser/download/download_browsertest.cc
index 37b9b858..6b5cb00 100644
--- a/content/browser/download/download_browsertest.cc
+++ b/content/browser/download/download_browsertest.cc
@@ -5,10 +5,14 @@
 // This file contains download browser tests that are known to be runnable
 // in a pure content context.  Over time tests should be migrated here.
 
+#include <vector>
+
+#include "base/callback_helpers.h"
 #include "base/command_line.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
+#include "base/format_macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
@@ -28,6 +32,7 @@
 #include "content/public/test/content_browser_test.h"
 #include "content/public/test/content_browser_test_utils.h"
 #include "content/public/test/download_test_observer.h"
+#include "content/public/test/test_download_request_handler.h"
 #include "content/public/test/test_file_error_injector.h"
 #include "content/public/test/test_utils.h"
 #include "content/shell/browser/shell.h"
@@ -37,7 +42,6 @@
 #include "net/test/embedded_test_server/embedded_test_server.h"
 #include "net/test/embedded_test_server/http_request.h"
 #include "net/test/embedded_test_server/http_response.h"
-#include "net/test/spawned_test_server/spawned_test_server.h"
 #include "net/test/url_request/url_request_mock_http_job.h"
 #include "net/test/url_request/url_request_slow_download_job.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -378,71 +382,11 @@
   std::vector<DownloadOpenDelayedCallback> delayed_callbacks_;
 };
 
-// Record all state transitions and byte counts on the observed download.
-class RecordingDownloadObserver : DownloadItem::Observer {
- public:
-  struct RecordStruct {
-    DownloadItem::DownloadState state;
-    int bytes_received;
-  };
-
-  typedef std::vector<RecordStruct> RecordVector;
-
-  RecordingDownloadObserver(DownloadItem* download)
-      : download_(download) {
-    last_state_.state = download->GetState();
-    last_state_.bytes_received = download->GetReceivedBytes();
-    download_->AddObserver(this);
-  }
-
-  ~RecordingDownloadObserver() override { RemoveObserver(); }
-
-  void CompareToExpectedRecord(const RecordStruct expected[], size_t size) {
-    EXPECT_EQ(size, record_.size());
-    int min = size > record_.size() ? record_.size() : size;
-    for (int i = 0; i < min; ++i) {
-      EXPECT_EQ(expected[i].state, record_[i].state) << "Iteration " << i;
-      EXPECT_EQ(expected[i].bytes_received, record_[i].bytes_received)
-          << "Iteration " << i;
-    }
-  }
-
- private:
-  void OnDownloadUpdated(DownloadItem* download) override {
-    DCHECK_EQ(download_, download);
-    DownloadItem::DownloadState state = download->GetState();
-    int bytes = download->GetReceivedBytes();
-    if (last_state_.state != state || last_state_.bytes_received > bytes) {
-      last_state_.state = state;
-      last_state_.bytes_received = bytes;
-      record_.push_back(last_state_);
-    }
-  }
-
-  void OnDownloadDestroyed(DownloadItem* download) override {
-    DCHECK_EQ(download_, download);
-    RemoveObserver();
-  }
-
-  void RemoveObserver() {
-    if (download_) {
-      download_->RemoveObserver(this);
-      download_ = NULL;
-    }
-  }
-
-  DownloadItem* download_;
-  RecordStruct last_state_;
-  RecordVector record_;
-};
-
 // Get the next created download.
 class DownloadCreateObserver : DownloadManager::Observer {
  public:
   DownloadCreateObserver(DownloadManager* manager)
-      : manager_(manager),
-        item_(NULL),
-        waiting_(false) {
+      : manager_(manager), item_(NULL) {
     manager_->AddObserver(this);
   }
 
@@ -463,16 +407,16 @@
     if (!item_)
       item_ = download;
 
-    if (waiting_)
-      base::MessageLoopForUI::current()->QuitWhenIdle();
+    if (!completion_closure_.is_null())
+      base::ResetAndReturn(&completion_closure_).Run();
   }
 
   DownloadItem* WaitForFinished() {
     DCHECK_CURRENTLY_ON(BrowserThread::UI);
     if (!item_) {
-      waiting_ = true;
-      RunMessageLoop();
-      waiting_ = false;
+      base::RunLoop run_loop;
+      completion_closure_ = run_loop.QuitClosure();
+      run_loop.Run();
     }
     return item_;
   }
@@ -480,28 +424,11 @@
  private:
   DownloadManager* manager_;
   DownloadItem* item_;
-  bool waiting_;
+  base::Closure completion_closure_;
 };
 
-
-// Filter for waiting for a certain number of bytes.
-bool DataReceivedFilter(int number_of_bytes, DownloadItem* download) {
-  return download->GetReceivedBytes() >= number_of_bytes;
-}
-
-// Filter for download completion.
-bool DownloadCompleteFilter(DownloadItem* download) {
-  return download->GetState() == DownloadItem::COMPLETE;
-}
-
-// Filter for saving the size of the download when the first IN_PROGRESS
-// is hit.
-bool InitialSizeFilter(int* download_size, DownloadItem* download) {
-  if (download->GetState() != DownloadItem::IN_PROGRESS)
-    return false;
-
-  *download_size = download->GetReceivedBytes();
-  return true;
+bool IsDownloadInState(DownloadItem::DownloadState state, DownloadItem* item) {
+  return item->GetState() == state;
 }
 
 // Request handler to be used with CreateRedirectHandler().
@@ -530,12 +457,15 @@
 // Request handler to be used with CreateBasicResponseHandler().
 scoped_ptr<net::test_server::HttpResponse> HandleRequestAndSendBasicResponse(
     const std::string& relative_url,
+    const base::StringPairs& headers,
     const std::string& content_type,
     const std::string& body,
     const net::test_server::HttpRequest& request) {
   scoped_ptr<net::test_server::BasicHttpResponse> response;
   if (request.relative_url == relative_url) {
     response.reset(new net::test_server::BasicHttpResponse);
+    for (const auto& pair : headers)
+      response->AddCustomHeader(pair.first, pair.second);
     response->set_content_type(content_type);
     response->set_content(body);
   }
@@ -546,27 +476,64 @@
 // HTTP 200 status code, a Content-Type header and a body.
 net::EmbeddedTestServer::HandleRequestCallback CreateBasicResponseHandler(
     const std::string& relative_url,
+    const base::StringPairs& headers,
     const std::string& content_type,
     const std::string& body) {
-  return base::Bind(
-      &HandleRequestAndSendBasicResponse, relative_url, content_type, body);
+  return base::Bind(&HandleRequestAndSendBasicResponse, relative_url, headers,
+                    content_type, body);
 }
 
-}  // namespace
+// Helper class to "flatten" handling of
+// TestDownloadRequestHandler::OnStartHandler.
+class TestRequestStartHandler {
+ public:
+  // Construct an OnStartHandler that can be set as the on_start_handler for
+  // TestDownloadRequestHandler::Parameters.
+  TestDownloadRequestHandler::OnStartHandler GetOnStartHandler() {
+    EXPECT_FALSE(used_) << "GetOnStartHandler() should only be called once for "
+                           "an instance of TestRequestStartHandler.";
+    used_ = true;
+    return base::Bind(&TestRequestStartHandler::OnStartHandler,
+                      base::Unretained(this));
+  }
+
+  // Wait until the OnStartHandlers returned in a prior call to
+  // GetOnStartHandler() is invoked.
+  void WaitForCallback() {
+    if (response_callback_.is_null())
+      run_loop_.Run();
+  }
+
+  // Respond to the OnStartHandler() invocation using |headers| and |error|.
+  void RespondWith(const std::string& headers, net::Error error) {
+    ASSERT_FALSE(response_callback_.is_null());
+    response_callback_.Run(headers, error);
+  }
+
+  // Return the headers returned from the invocation of OnStartHandler.
+  const net::HttpRequestHeaders& headers() const {
+    EXPECT_FALSE(response_callback_.is_null());
+    return request_headers_;
+  }
+
+ private:
+  void OnStartHandler(const net::HttpRequestHeaders& headers,
+                      const TestDownloadRequestHandler::OnStartResponseCallback&
+                          response_callback) {
+    request_headers_ = headers;
+    response_callback_ = response_callback;
+    if (run_loop_.running())
+      run_loop_.Quit();
+  }
+
+  bool used_ = false;
+  base::RunLoop run_loop_;
+  net::HttpRequestHeaders request_headers_;
+  TestDownloadRequestHandler::OnStartResponseCallback response_callback_;
+};
 
 class DownloadContentTest : public ContentBrowserTest {
  protected:
-  // An initial send from a website of at least this size will not be
-  // help up by buffering in the underlying downloads ByteStream data
-  // transfer.  This is important because on resumption tests we wait
-  // until we've gotten the data we expect before allowing the test server
-  // to send its reset, to get around hard close semantics on the Windows
-  // socket layer implementation.
-  int GetSafeBufferChunk() const {
-    return (DownloadResourceHandler::kDownloadByteStreamSize /
-       ByteStreamWriter::kFractionBufferBeforeSending) + 1;
-  }
-
   void SetUpOnMainThread() override {
     ASSERT_TRUE(downloads_directory_.CreateUniqueTempDir());
 
@@ -601,19 +568,22 @@
         DownloadTestObserver::ON_DANGEROUS_DOWNLOAD_FAIL);
   }
 
-  // Create a DownloadTestObserverInProgress that will wait for the
-  // specified number of downloads to start.
-  DownloadCreateObserver* CreateInProgressWaiter(
-      Shell* shell, int num_downloads) {
-    DownloadManager* download_manager = DownloadManagerForShell(shell);
-    return new DownloadCreateObserver(download_manager);
+  void WaitForInterrupt(DownloadItem* download) {
+    DownloadUpdatedObserver(
+        download, base::Bind(&IsDownloadInState, DownloadItem::INTERRUPTED))
+        .WaitForEvent();
   }
 
-  DownloadTestObserver* CreateInterruptedWaiter(
-      Shell* shell, int num_downloads) {
-    DownloadManager* download_manager = DownloadManagerForShell(shell);
-    return new DownloadTestObserverInterrupted(download_manager, num_downloads,
-        DownloadTestObserver::ON_DANGEROUS_DOWNLOAD_FAIL);
+  void WaitForInProgress(DownloadItem* download) {
+    DownloadUpdatedObserver(
+        download, base::Bind(&IsDownloadInState, DownloadItem::IN_PROGRESS))
+        .WaitForEvent();
+  }
+
+  void WaitForCompletion(DownloadItem* download) {
+    DownloadUpdatedObserver(
+        download, base::Bind(&IsDownloadInState, DownloadItem::COMPLETE))
+        .WaitForEvent();
   }
 
   // Note: Cannot be used with other alternative DownloadFileFactorys
@@ -675,67 +645,35 @@
   // Start a download and return the item.
   DownloadItem* StartDownloadAndReturnItem(GURL url) {
     scoped_ptr<DownloadCreateObserver> observer(
-        CreateInProgressWaiter(shell(), 1));
-    NavigateToURL(shell(), url);
-    observer->WaitForFinished();
-    std::vector<DownloadItem*> downloads;
-    DownloadManagerForShell(shell())->GetAllDownloads(&downloads);
-    EXPECT_EQ(1u, downloads.size());
-    if (1u != downloads.size())
-      return NULL;
-    return downloads[0];
+        new DownloadCreateObserver(DownloadManagerForShell(shell())));
+    shell()->LoadURL(url);
+    return observer->WaitForFinished();
   }
 
-  // Wait for data
-  void WaitForData(DownloadItem* download, int size) {
-    DownloadUpdatedObserver data_observer(
-        download, base::Bind(&DataReceivedFilter, size));
-    data_observer.WaitForEvent();
-    ASSERT_EQ(size, download->GetReceivedBytes());
-    ASSERT_EQ(DownloadItem::IN_PROGRESS, download->GetState());
-  }
+  static void ReadAndVerifyFileContents(int seed,
+                                        int64_t expected_size,
+                                        const base::FilePath& path) {
+    base::File file(path, base::File::FLAG_OPEN | base::File::FLAG_READ);
+    ASSERT_TRUE(file.IsValid());
+    int64_t file_length = file.GetLength();
+    ASSERT_EQ(expected_size, file_length);
 
-  // Tell the test server to release a pending RST and confirm
-  // that the interrupt is received properly (for download resumption
-  // testing).
-  void ReleaseRSTAndConfirmInterruptForResume(DownloadItem* download) {
-    scoped_ptr<DownloadTestObserver> rst_observer(
-        CreateInterruptedWaiter(shell(), 1));
-    NavigateToURL(shell(), spawned_test_server()->GetURL("download-finish"));
-    rst_observer->WaitForFinished();
-    EXPECT_EQ(DownloadItem::INTERRUPTED, download->GetState());
-  }
+    const int64_t kBufferSize = 64 * 1024;
+    std::vector<char> pattern;
+    std::vector<char> data;
+    pattern.resize(kBufferSize);
+    data.resize(kBufferSize);
+    for (int64_t offset = 0; offset < file_length;) {
+      int bytes_read = file.Read(offset, &data.front(), kBufferSize);
+      ASSERT_LT(0, bytes_read);
+      ASSERT_GE(kBufferSize, bytes_read);
 
-  // Confirm file status expected for the given location in a stream
-  // provided by the resume test server.
-  void ConfirmFileStatusForResume(
-      DownloadItem* download, bool file_exists,
-      int received_bytes, int total_bytes,
-      const base::FilePath& expected_filename) {
-    // expected_filename is only known if the file exists.
-    ASSERT_EQ(file_exists, !expected_filename.empty());
-    EXPECT_EQ(received_bytes, download->GetReceivedBytes());
-    EXPECT_EQ(total_bytes, download->GetTotalBytes());
-    EXPECT_EQ(expected_filename.value(),
-              download->GetFullPath().BaseName().value());
-    EXPECT_EQ(file_exists,
-              (!download->GetFullPath().empty() &&
-               base::PathExists(download->GetFullPath())));
-
-    if (file_exists) {
-      std::string file_contents;
-      EXPECT_TRUE(base::ReadFileToString(
-          download->GetFullPath(), &file_contents));
-
-      ASSERT_EQ(static_cast<size_t>(received_bytes), file_contents.size());
-      for (int i = 0; i < received_bytes; ++i) {
-        EXPECT_EQ(static_cast<char>((i * 2 + 15) % 256), file_contents[i])
-            << "File contents diverged at position " << i
-            << " for " << expected_filename.value();
-
-        if (static_cast<char>((i * 2 + 15) % 256) != file_contents[i])
-          return;
-      }
+      TestDownloadRequestHandler::GetPatternBytes(seed, offset, bytes_read,
+                                                  &pattern.front());
+      ASSERT_EQ(0, memcmp(&pattern.front(), &data.front(), bytes_read))
+          << "Comparing block at offset " << offset << " and length "
+          << bytes_read;
+      offset += bytes_read;
     }
   }
 
@@ -752,23 +690,19 @@
   scoped_ptr<TestShellDownloadManagerDelegate> test_delegate_;
 };
 
+}  // namespace
+
 IN_PROC_BROWSER_TEST_F(DownloadContentTest, DownloadCancelled) {
   SetupEnsureNoPendingDownloads();
 
   // Create a download, wait until it's started, and confirm
   // we're in the expected state.
-  scoped_ptr<DownloadCreateObserver> observer(
-      CreateInProgressWaiter(shell(), 1));
-  NavigateToURL(shell(), GURL(net::URLRequestSlowDownloadJob::kUnknownSizeUrl));
-  observer->WaitForFinished();
-
-  std::vector<DownloadItem*> downloads;
-  DownloadManagerForShell(shell())->GetAllDownloads(&downloads);
-  ASSERT_EQ(1u, downloads.size());
-  ASSERT_EQ(DownloadItem::IN_PROGRESS, downloads[0]->GetState());
+  DownloadItem* download = StartDownloadAndReturnItem(
+      GURL(net::URLRequestSlowDownloadJob::kUnknownSizeUrl));
+  ASSERT_EQ(DownloadItem::IN_PROGRESS, download->GetState());
 
   // Cancel the download and wait for download system quiesce.
-  downloads[0]->Cancel(true);
+  download->Cancel(true);
   scoped_refptr<DownloadTestFlushObserver> flush_observer(
       new DownloadTestFlushObserver(DownloadManagerForShell(shell())));
   flush_observer->WaitForFlush();
@@ -784,28 +718,14 @@
 
   // Create a download, wait until it's started, and confirm
   // we're in the expected state.
-  scoped_ptr<DownloadCreateObserver> observer1(
-      CreateInProgressWaiter(shell(), 1));
-  NavigateToURL(shell(), GURL(net::URLRequestSlowDownloadJob::kUnknownSizeUrl));
-  observer1->WaitForFinished();
-
-  std::vector<DownloadItem*> downloads;
-  DownloadManagerForShell(shell())->GetAllDownloads(&downloads);
-  ASSERT_EQ(1u, downloads.size());
-  ASSERT_EQ(DownloadItem::IN_PROGRESS, downloads[0]->GetState());
-  DownloadItem* download1 = downloads[0];  // The only download.
+  DownloadItem* download1 = StartDownloadAndReturnItem(
+      GURL(net::URLRequestSlowDownloadJob::kUnknownSizeUrl));
+  ASSERT_EQ(DownloadItem::IN_PROGRESS, download1->GetState());
 
   // Start the second download and wait until it's done.
   GURL url(net::URLRequestMockHTTPJob::GetMockUrl("download-test.lib"));
-  // Download the file and wait.
-  NavigateToURLAndWaitForDownload(shell(), url, DownloadItem::COMPLETE);
-
-  // Should now have 2 items on the manager.
-  downloads.clear();
-  DownloadManagerForShell(shell())->GetAllDownloads(&downloads);
-  ASSERT_EQ(2u, downloads.size());
-  // We don't know the order of the downloads.
-  DownloadItem* download2 = downloads[(download1 == downloads[0]) ? 1 : 0];
+  DownloadItem* download2 = StartDownloadAndReturnItem(url);
+  WaitForCompletion(download2);
 
   ASSERT_EQ(DownloadItem::IN_PROGRESS, download1->GetState());
   ASSERT_EQ(DownloadItem::COMPLETE, download2->GetState());
@@ -962,21 +882,15 @@
 // works properly.
 IN_PROC_BROWSER_TEST_F(DownloadContentTest, ShutdownInProgress) {
   // Create a download that won't complete.
-  scoped_ptr<DownloadCreateObserver> observer(
-      CreateInProgressWaiter(shell(), 1));
-  NavigateToURL(shell(), GURL(net::URLRequestSlowDownloadJob::kUnknownSizeUrl));
-  observer->WaitForFinished();
+  DownloadItem* download = StartDownloadAndReturnItem(
+      GURL(net::URLRequestSlowDownloadJob::kUnknownSizeUrl));
 
-  // Get the item.
-  std::vector<DownloadItem*> items;
-  DownloadManagerForShell(shell())->GetAllDownloads(&items);
-  ASSERT_EQ(1u, items.size());
-  EXPECT_EQ(DownloadItem::IN_PROGRESS, items[0]->GetState());
+  EXPECT_EQ(DownloadItem::IN_PROGRESS, download->GetState());
 
   // Shutdown the download manager and make sure we get the right
   // notifications in the right order.
   StrictMock<MockDownloadItemObserver> item_observer;
-  items[0]->AddObserver(&item_observer);
+  download->AddObserver(&item_observer);
   MockDownloadManagerObserver manager_observer(
       DownloadManagerForShell(shell()));
   // Don't care about ModelChanged() events.
@@ -988,11 +902,12 @@
     EXPECT_CALL(manager_observer, MockManagerGoingDown(
         DownloadManagerForShell(shell())))
         .WillOnce(Return());
-    EXPECT_CALL(item_observer, OnDownloadUpdated(
-        AllOf(items[0],
-              Property(&DownloadItem::GetState, DownloadItem::CANCELLED))))
+    EXPECT_CALL(
+        item_observer,
+        OnDownloadUpdated(AllOf(download, Property(&DownloadItem::GetState,
+                                                   DownloadItem::CANCELLED))))
         .WillOnce(Return());
-    EXPECT_CALL(item_observer, OnDownloadDestroyed(items[0]))
+    EXPECT_CALL(item_observer, OnDownloadDestroyed(download))
         .WillOnce(Return());
   }
 
@@ -1009,7 +924,6 @@
   BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
                           base::Bind(&base::PlatformThread::Sleep,
                                      base::TimeDelta::FromMilliseconds(25)));
-  items.clear();
 }
 
 // Try to shutdown just after we release the download file, by delaying
@@ -1068,237 +982,222 @@
   DownloadManagerForShell(shell())->Shutdown();
 }
 
-IN_PROC_BROWSER_TEST_F(DownloadContentTest, ResumeInterruptedDownload) {
+// Test resumption with a response that contains strong validators.
+IN_PROC_BROWSER_TEST_F(DownloadContentTest, Resume_WithStrongValidators) {
   base::CommandLine::ForCurrentProcess()->AppendSwitch(
       switches::kEnableDownloadResumption);
-  ASSERT_TRUE(spawned_test_server()->Start());
 
-  GURL url = spawned_test_server()->GetURL(
-      base::StringPrintf("rangereset?size=%d&rst_boundary=%d",
-                         GetSafeBufferChunk() * 3, GetSafeBufferChunk()));
+  TestDownloadRequestHandler request_handler;
+  TestDownloadRequestHandler::Parameters parameters =
+      TestDownloadRequestHandler::Parameters::WithSingleInterruption();
+  const TestDownloadRequestHandler::InjectedError interruption =
+      parameters.injected_errors.front();
+  request_handler.StartServing(parameters);
 
-  MockDownloadManagerObserver dm_observer(DownloadManagerForShell(shell()));
-  EXPECT_CALL(dm_observer, OnDownloadCreated(_,_)).Times(1);
+  DownloadItem* download = StartDownloadAndReturnItem(request_handler.url());
+  WaitForInterrupt(download);
 
-  DownloadItem* download(StartDownloadAndReturnItem(url));
-  WaitForData(download, GetSafeBufferChunk());
-  ::testing::Mock::VerifyAndClearExpectations(&dm_observer);
+  ASSERT_EQ(interruption.offset, download->GetReceivedBytes());
+  ASSERT_EQ(parameters.size, download->GetTotalBytes());
 
-  // Confirm resumption while in progress doesn't do anything.
   download->Resume();
-  ASSERT_EQ(GetSafeBufferChunk(), download->GetReceivedBytes());
-  ASSERT_EQ(DownloadItem::IN_PROGRESS, download->GetState());
+  WaitForCompletion(download);
 
-  // Tell the server to send the RST and confirm the interrupt happens.
-  ReleaseRSTAndConfirmInterruptForResume(download);
-  ConfirmFileStatusForResume(
-      download, true, GetSafeBufferChunk(), GetSafeBufferChunk() * 3,
-      base::FilePath(FILE_PATH_LITERAL("rangereset.crdownload")));
+  ASSERT_EQ(parameters.size, download->GetReceivedBytes());
+  ASSERT_EQ(parameters.size, download->GetTotalBytes());
+  ASSERT_NO_FATAL_FAILURE(ReadAndVerifyFileContents(
+      parameters.pattern_generator_seed, parameters.size,
+      download->GetTargetFilePath()));
 
-  // Resume, confirming received bytes on resumption is correct.
-  // Make sure no creation calls are included.
-  EXPECT_CALL(dm_observer, OnDownloadCreated(_,_)).Times(0);
-  int initial_size = 0;
-  DownloadUpdatedObserver initial_size_observer(
-      download, base::Bind(&InitialSizeFilter, &initial_size));
-  download->Resume();
-  initial_size_observer.WaitForEvent();
-  EXPECT_EQ(GetSafeBufferChunk(), initial_size);
-  ::testing::Mock::VerifyAndClearExpectations(&dm_observer);
+  // Characterization risk: The next portion of the test examines the requests
+  // that were sent out while downloading our resource. These requests
+  // correspond to the requests that were generated by the browser and the
+  // downloads system and may change as implementation details change.
+  TestDownloadRequestHandler::CompletedRequests requests;
+  request_handler.GetCompletedRequestInfo(&requests);
 
-  // and wait for expected data.
-  WaitForData(download, GetSafeBufferChunk() * 2);
+  ASSERT_EQ(2u, requests.size());
 
-  // Tell the server to send the RST and confirm the interrupt happens.
-  ReleaseRSTAndConfirmInterruptForResume(download);
-  ConfirmFileStatusForResume(
-      download, true, GetSafeBufferChunk() * 2, GetSafeBufferChunk() * 3,
-      base::FilePath(FILE_PATH_LITERAL("rangereset.crdownload")));
+  // The first request only transferrs bytes up until the interruption point.
+  EXPECT_EQ(interruption.offset, requests[0].transferred_byte_count);
 
-  // Resume and wait for completion.
-  DownloadUpdatedObserver completion_observer(
-      download, base::Bind(DownloadCompleteFilter));
-  download->Resume();
-  completion_observer.WaitForEvent();
+  // The next request should only have transferred the remainder of the
+  // resource.
+  EXPECT_EQ(parameters.size - interruption.offset,
+            requests[1].transferred_byte_count);
 
-  ConfirmFileStatusForResume(
-      download, true, GetSafeBufferChunk() * 3, GetSafeBufferChunk() * 3,
-      base::FilePath(FILE_PATH_LITERAL("rangereset")));
+  std::string value;
+  ASSERT_TRUE(requests[1].request_headers.GetHeader(
+      net::HttpRequestHeaders::kIfRange, &value));
+  EXPECT_EQ(parameters.etag, value);
 
-  // Confirm resumption while complete doesn't do anything.
-  download->Resume();
-  ASSERT_EQ(GetSafeBufferChunk() * 3, download->GetReceivedBytes());
-  ASSERT_EQ(DownloadItem::COMPLETE, download->GetState());
-  RunAllPendingInMessageLoop();
-  ASSERT_EQ(GetSafeBufferChunk() * 3, download->GetReceivedBytes());
-  ASSERT_EQ(DownloadItem::COMPLETE, download->GetState());
+  ASSERT_TRUE(requests[1].request_headers.GetHeader(
+      net::HttpRequestHeaders::kRange, &value));
+  EXPECT_EQ(base::StringPrintf("bytes=%" PRId64 "-", interruption.offset),
+            value);
 }
 
-// Confirm restart fallback happens if a range request is bounced.
-IN_PROC_BROWSER_TEST_F(DownloadContentTest, ResumeInterruptedDownloadNoRange) {
-  base::CommandLine::ForCurrentProcess()->AppendSwitch(
-      switches::kEnableDownloadResumption);
-  ASSERT_TRUE(spawned_test_server()->Start());
-
-  // Auto-restart if server doesn't handle ranges.
-  GURL url = spawned_test_server()->GetURL(base::StringPrintf(
-      // First download hits an RST, rest don't, no ranges.
-      "rangereset?size=%d&rst_boundary=%d&"
-      "token=NoRange&rst_limit=1&bounce_range",
-      GetSafeBufferChunk() * 3, GetSafeBufferChunk()));
-
-  // Start the download and wait for first data chunk.
-  DownloadItem* download(StartDownloadAndReturnItem(url));
-  WaitForData(download, GetSafeBufferChunk());
-
-  RecordingDownloadObserver recorder(download);
-
-  ReleaseRSTAndConfirmInterruptForResume(download);
-  ConfirmFileStatusForResume(
-      download, true, GetSafeBufferChunk(), GetSafeBufferChunk() * 3,
-      base::FilePath(FILE_PATH_LITERAL("rangereset.crdownload")));
-
-  DownloadUpdatedObserver completion_observer(
-      download, base::Bind(DownloadCompleteFilter));
-  download->Resume();
-  completion_observer.WaitForEvent();
-
-  ConfirmFileStatusForResume(
-      download, true, GetSafeBufferChunk() * 3, GetSafeBufferChunk() * 3,
-      base::FilePath(FILE_PATH_LITERAL("rangereset")));
-
-  static const RecordingDownloadObserver::RecordStruct expected_record[] = {
-    // Result of RST
-    {DownloadItem::INTERRUPTED, GetSafeBufferChunk()},
-    // Starting continuation
-    {DownloadItem::IN_PROGRESS, GetSafeBufferChunk()},
-    // Notification of receiving whole file.
-    {DownloadItem::IN_PROGRESS, 0},
-    // Completion.
-    {DownloadItem::COMPLETE, GetSafeBufferChunk() * 3},
-  };
-
-  recorder.CompareToExpectedRecord(expected_record, arraysize(expected_record));
-}
-
-// Confirm we don't try to resume if we don't have a verifier.
+// A partial resumption results in an HTTP 200 response. I.e. the server ignored
+// the range request and sent the entire resource instead. For If-Range requests
+// (as opposed to If-Match), the behavior for a precondition failure is also to
+// respond with a 200. So this test case covers both validation failure and
+// ignoring the range request.
 IN_PROC_BROWSER_TEST_F(DownloadContentTest,
-                       ResumeInterruptedDownloadNoVerifiers) {
+                       Resume_RestartIfNotPartialResponse) {
   base::CommandLine::ForCurrentProcess()->AppendSwitch(
       switches::kEnableDownloadResumption);
-  ASSERT_TRUE(spawned_test_server()->Start());
+  const int kOriginalPatternGeneratorSeed = 1;
+  const int kNewPatternGeneratorSeed = 2;
 
-  GURL url = spawned_test_server()->GetURL(base::StringPrintf(
-      // First download hits an RST, rest don't, no verifiers.
-      "rangereset?size=%d&rst_boundary=%d&"
-      "token=NoRange&rst_limit=1&no_verifiers",
-      GetSafeBufferChunk() * 3, GetSafeBufferChunk()));
+  TestDownloadRequestHandler::Parameters parameters =
+      TestDownloadRequestHandler::Parameters::WithSingleInterruption();
+  parameters.pattern_generator_seed = kOriginalPatternGeneratorSeed;
+  const TestDownloadRequestHandler::InjectedError interruption =
+      parameters.injected_errors.front();
 
-  // Start the download and wait for first data chunk.
-  DownloadItem* download(StartDownloadAndReturnItem(url));
-  WaitForData(download, GetSafeBufferChunk());
+  TestDownloadRequestHandler request_handler;
+  request_handler.StartServing(parameters);
 
-  RecordingDownloadObserver recorder(download);
+  DownloadItem* download = StartDownloadAndReturnItem(request_handler.url());
+  WaitForInterrupt(download);
 
-  ReleaseRSTAndConfirmInterruptForResume(download);
-  ConfirmFileStatusForResume(
-      download, false, GetSafeBufferChunk(), GetSafeBufferChunk() * 3,
-      base::FilePath());
+  ASSERT_EQ(interruption.offset, download->GetReceivedBytes());
+  ASSERT_EQ(parameters.size, download->GetTotalBytes());
 
-  DownloadUpdatedObserver completion_observer(
-      download, base::Bind(DownloadCompleteFilter));
+  parameters = TestDownloadRequestHandler::Parameters();
+  parameters.support_byte_ranges = false;
+  parameters.pattern_generator_seed = kNewPatternGeneratorSeed;
+  request_handler.StartServing(parameters);
+
   download->Resume();
-  completion_observer.WaitForEvent();
+  WaitForCompletion(download);
 
-  ConfirmFileStatusForResume(
-      download, true, GetSafeBufferChunk() * 3, GetSafeBufferChunk() * 3,
-      base::FilePath(FILE_PATH_LITERAL("rangereset")));
+  ASSERT_EQ(parameters.size, download->GetReceivedBytes());
+  ASSERT_EQ(parameters.size, download->GetTotalBytes());
+  ASSERT_NO_FATAL_FAILURE(
+      ReadAndVerifyFileContents(kNewPatternGeneratorSeed, parameters.size,
+                                download->GetTargetFilePath()));
 
-  static const RecordingDownloadObserver::RecordStruct expected_record[] = {
-    // Result of RST
-    {DownloadItem::INTERRUPTED, GetSafeBufferChunk()},
-    // Restart for lack of verifiers
-    {DownloadItem::IN_PROGRESS, 0},
-    // Completion.
-    {DownloadItem::COMPLETE, GetSafeBufferChunk() * 3},
-  };
+  // When the downloads system sees the full response, it should accept the
+  // response without restarting. On the network, we should deterministically
+  // see two requests:
+  // * The original request which transfers upto our interruption point.
+  // * The resumption attempt, which receives the entire entity.
+  TestDownloadRequestHandler::CompletedRequests requests;
+  request_handler.GetCompletedRequestInfo(&requests);
 
-  recorder.CompareToExpectedRecord(expected_record, arraysize(expected_record));
+  ASSERT_EQ(2u, requests.size());
+
+  // The first request only transfers data up to the interruption point.
+  EXPECT_EQ(interruption.offset, requests[0].transferred_byte_count);
+
+  // The second request transfers the entire response.
+  EXPECT_EQ(parameters.size, requests[1].transferred_byte_count);
+
+  std::string value;
+  ASSERT_TRUE(requests[1].request_headers.GetHeader(
+      net::HttpRequestHeaders::kIfRange, &value));
+  EXPECT_EQ(parameters.etag, value);
+
+  ASSERT_TRUE(requests[1].request_headers.GetHeader(
+      net::HttpRequestHeaders::kRange, &value));
+  EXPECT_EQ(base::StringPrintf("bytes=%" PRId64 "-", interruption.offset),
+            value);
 }
 
-IN_PROC_BROWSER_TEST_F(DownloadContentTest, ResumeWithDeletedFile) {
+// Confirm we restart if we don't have a verifier.
+IN_PROC_BROWSER_TEST_F(DownloadContentTest, Resume_RestartIfNoETag) {
   base::CommandLine::ForCurrentProcess()->AppendSwitch(
       switches::kEnableDownloadResumption);
-  ASSERT_TRUE(spawned_test_server()->Start());
+  const int kOriginalPatternGeneratorSeed = 1;
+  const int kNewPatternGeneratorSeed = 2;
 
-  GURL url = spawned_test_server()->GetURL(base::StringPrintf(
-      // First download hits an RST, rest don't
-      "rangereset?size=%d&rst_boundary=%d&"
-      "token=NoRange&rst_limit=1",
-      GetSafeBufferChunk() * 3, GetSafeBufferChunk()));
+  TestDownloadRequestHandler::Parameters parameters =
+      TestDownloadRequestHandler::Parameters::WithSingleInterruption();
+  ASSERT_EQ(1u, parameters.injected_errors.size());
+  parameters.etag.clear();
+  parameters.pattern_generator_seed = kOriginalPatternGeneratorSeed;
 
-  // Start the download and wait for first data chunk.
-  DownloadItem* download(StartDownloadAndReturnItem(url));
-  WaitForData(download, GetSafeBufferChunk());
+  TestDownloadRequestHandler request_handler;
+  request_handler.StartServing(parameters);
+  DownloadItem* download = StartDownloadAndReturnItem(request_handler.url());
+  WaitForInterrupt(download);
 
-  RecordingDownloadObserver recorder(download);
+  parameters.pattern_generator_seed = kNewPatternGeneratorSeed;
+  parameters.ClearInjectedErrors();
+  request_handler.StartServing(parameters);
 
-  ReleaseRSTAndConfirmInterruptForResume(download);
-  ConfirmFileStatusForResume(
-      download, true, GetSafeBufferChunk(), GetSafeBufferChunk() * 3,
-      base::FilePath(FILE_PATH_LITERAL("rangereset.crdownload")));
+  download->Resume();
+  WaitForCompletion(download);
+
+  ASSERT_EQ(parameters.size, download->GetReceivedBytes());
+  ASSERT_EQ(parameters.size, download->GetTotalBytes());
+  ASSERT_NO_FATAL_FAILURE(
+      ReadAndVerifyFileContents(kNewPatternGeneratorSeed, parameters.size,
+                                download->GetTargetFilePath()));
+
+  TestDownloadRequestHandler::CompletedRequests requests;
+  request_handler.GetCompletedRequestInfo(&requests);
+
+  // Neither If-Range nor Range headers should be present in the second request.
+  ASSERT_EQ(2u, requests.size());
+  std::string value;
+  EXPECT_FALSE(requests[1].request_headers.GetHeader(
+      net::HttpRequestHeaders::kIfRange, &value));
+  EXPECT_FALSE(requests[1].request_headers.GetHeader(
+      net::HttpRequestHeaders::kRange, &value));
+}
+
+// Partial file goes missing before the download is resumed. The download should
+// restart.
+IN_PROC_BROWSER_TEST_F(DownloadContentTest, Resume_RestartIfNoPartialFile) {
+  base::CommandLine::ForCurrentProcess()->AppendSwitch(
+      switches::kEnableDownloadResumption);
+  TestDownloadRequestHandler::Parameters parameters =
+      TestDownloadRequestHandler::Parameters::WithSingleInterruption();
+
+  TestDownloadRequestHandler request_handler;
+  request_handler.StartServing(parameters);
+  DownloadItem* download = StartDownloadAndReturnItem(request_handler.url());
+  WaitForInterrupt(download);
 
   // Delete the intermediate file.
-  base::DeleteFile(download->GetFullPath(), false);
+  ASSERT_TRUE(base::PathExists(download->GetFullPath()));
+  ASSERT_TRUE(base::DeleteFile(download->GetFullPath(), false));
 
-  DownloadUpdatedObserver completion_observer(
-      download, base::Bind(DownloadCompleteFilter));
+  parameters.ClearInjectedErrors();
+  request_handler.StartServing(parameters);
+
   download->Resume();
-  completion_observer.WaitForEvent();
+  WaitForCompletion(download);
 
-  ConfirmFileStatusForResume(
-      download, true, GetSafeBufferChunk() * 3, GetSafeBufferChunk() * 3,
-      base::FilePath(FILE_PATH_LITERAL("rangereset")));
-
-  static const RecordingDownloadObserver::RecordStruct expected_record[] = {
-    // Result of RST
-    {DownloadItem::INTERRUPTED, GetSafeBufferChunk()},
-    // Starting continuation
-    {DownloadItem::IN_PROGRESS, GetSafeBufferChunk()},
-    // Error because file isn't there.
-    {DownloadItem::INTERRUPTED, 0},
-    // Restart.
-    {DownloadItem::IN_PROGRESS, 0},
-    // Completion.
-    {DownloadItem::COMPLETE, GetSafeBufferChunk() * 3},
-  };
-
-  recorder.CompareToExpectedRecord(expected_record, arraysize(expected_record));
+  ASSERT_EQ(parameters.size, download->GetReceivedBytes());
+  ASSERT_EQ(parameters.size, download->GetTotalBytes());
+  ASSERT_NO_FATAL_FAILURE(ReadAndVerifyFileContents(
+      parameters.pattern_generator_seed, parameters.size,
+      download->GetTargetFilePath()));
 }
 
-IN_PROC_BROWSER_TEST_F(DownloadContentTest, ResumeWithFileInitError) {
+IN_PROC_BROWSER_TEST_F(DownloadContentTest, Resume_RecoverFromInitFileError) {
   base::CommandLine::ForCurrentProcess()->AppendSwitch(
       switches::kEnableDownloadResumption);
-  GURL url(net::URLRequestMockHTTPJob::GetMockUrl("download-test.lib"));
+  TestDownloadRequestHandler request_handler;
+  request_handler.StartServing(TestDownloadRequestHandler::Parameters());
 
   // Setup the error injector.
   scoped_refptr<TestFileErrorInjector> injector(
       TestFileErrorInjector::Create(DownloadManagerForShell(shell())));
 
-  TestFileErrorInjector::FileErrorInfo err = {
-    url.spec(),
-    TestFileErrorInjector::FILE_OPERATION_INITIALIZE,
-    0,
-    DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE
-  };
+  const TestFileErrorInjector::FileErrorInfo err = {
+      request_handler.url().spec(),
+      TestFileErrorInjector::FILE_OPERATION_INITIALIZE, 0,
+      DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE};
   injector->AddError(err);
   injector->InjectErrors();
 
   // Start and watch for interrupt.
-  scoped_ptr<DownloadTestObserver> int_observer(
-      CreateInterruptedWaiter(shell(), 1));
-  DownloadItem* download(StartDownloadAndReturnItem(url));
-  int_observer->WaitForFinished();
+  DownloadItem* download(StartDownloadAndReturnItem(request_handler.url()));
+  WaitForInterrupt(download);
   ASSERT_EQ(DownloadItem::INTERRUPTED, download->GetState());
   EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE,
             download->GetLastReason());
@@ -1318,37 +1217,32 @@
   injector->InjectErrors();
 
   // Resume and watch completion.
-  DownloadUpdatedObserver completion_observer(
-      download, base::Bind(DownloadCompleteFilter));
   download->Resume();
-  completion_observer.WaitForEvent();
+  WaitForCompletion(download);
   EXPECT_EQ(download->GetState(), DownloadItem::COMPLETE);
 }
 
 IN_PROC_BROWSER_TEST_F(DownloadContentTest,
-                       ResumeWithFileIntermediateRenameError) {
+                       Resume_RecoverFromIntermediateFileRenameError) {
   base::CommandLine::ForCurrentProcess()->AppendSwitch(
       switches::kEnableDownloadResumption);
-  GURL url(net::URLRequestMockHTTPJob::GetMockUrl("download-test.lib"));
+  TestDownloadRequestHandler request_handler;
+  request_handler.StartServing(TestDownloadRequestHandler::Parameters());
 
   // Setup the error injector.
   scoped_refptr<TestFileErrorInjector> injector(
       TestFileErrorInjector::Create(DownloadManagerForShell(shell())));
 
-  TestFileErrorInjector::FileErrorInfo err = {
-    url.spec(),
-    TestFileErrorInjector::FILE_OPERATION_RENAME_UNIQUIFY,
-    0,
-    DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE
-  };
+  const TestFileErrorInjector::FileErrorInfo err = {
+      request_handler.url().spec(),
+      TestFileErrorInjector::FILE_OPERATION_RENAME_UNIQUIFY, 0,
+      DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE};
   injector->AddError(err);
   injector->InjectErrors();
 
   // Start and watch for interrupt.
-  scoped_ptr<DownloadTestObserver> int_observer(
-      CreateInterruptedWaiter(shell(), 1));
-  DownloadItem* download(StartDownloadAndReturnItem(url));
-  int_observer->WaitForFinished();
+  DownloadItem* download(StartDownloadAndReturnItem(request_handler.url()));
+  WaitForInterrupt(download);
   ASSERT_EQ(DownloadItem::INTERRUPTED, download->GetState());
   EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE,
             download->GetLastReason());
@@ -1369,18 +1263,17 @@
   injector->ClearErrors();
   injector->InjectErrors();
 
-  // Resume and watch completion.
-  DownloadUpdatedObserver completion_observer(
-      download, base::Bind(DownloadCompleteFilter));
   download->Resume();
-  completion_observer.WaitForEvent();
+  WaitForCompletion(download);
   EXPECT_EQ(download->GetState(), DownloadItem::COMPLETE);
 }
 
-IN_PROC_BROWSER_TEST_F(DownloadContentTest, ResumeWithFileFinalRenameError) {
+IN_PROC_BROWSER_TEST_F(DownloadContentTest,
+                       Resume_RecoverFromFinalRenameError) {
   base::CommandLine::ForCurrentProcess()->AppendSwitch(
       switches::kEnableDownloadResumption);
-  GURL url(net::URLRequestMockHTTPJob::GetMockUrl("download-test.lib"));
+  TestDownloadRequestHandler request_handler;
+  request_handler.StartServing(TestDownloadRequestHandler::Parameters());
 
   // Setup the error injector.
   scoped_refptr<TestFileErrorInjector> injector(
@@ -1388,19 +1281,15 @@
 
   DownloadManagerForShell(shell())->RemoveAllDownloads();
   TestFileErrorInjector::FileErrorInfo err = {
-    url.spec(),
-    TestFileErrorInjector::FILE_OPERATION_RENAME_ANNOTATE,
-    0,
-    DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE
-  };
+      request_handler.url().spec(),
+      TestFileErrorInjector::FILE_OPERATION_RENAME_ANNOTATE, 0,
+      DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE};
   injector->AddError(err);
   injector->InjectErrors();
 
   // Start and watch for interrupt.
-  scoped_ptr<DownloadTestObserver> int_observer(
-      CreateInterruptedWaiter(shell(), 1));
-  DownloadItem* download(StartDownloadAndReturnItem(url));
-  int_observer->WaitForFinished();
+  DownloadItem* download(StartDownloadAndReturnItem(request_handler.url()));
+  WaitForInterrupt(download);
   ASSERT_EQ(DownloadItem::INTERRUPTED, download->GetState());
   EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE,
             download->GetLastReason());
@@ -1419,11 +1308,8 @@
   injector->ClearErrors();
   injector->InjectErrors();
 
-  // Resume and watch completion.
-  DownloadUpdatedObserver completion_observer(
-      download, base::Bind(DownloadCompleteFilter));
   download->Resume();
-  completion_observer.WaitForEvent();
+  WaitForCompletion(download);
   EXPECT_EQ(download->GetState(), DownloadItem::COMPLETE);
 }
 
@@ -1432,23 +1318,16 @@
 IN_PROC_BROWSER_TEST_F(DownloadContentTest, CancelInterruptedDownload) {
   base::CommandLine::ForCurrentProcess()->AppendSwitch(
       switches::kEnableDownloadResumption);
-  ASSERT_TRUE(spawned_test_server()->Start());
+  TestDownloadRequestHandler request_handler;
+  request_handler.StartServing(
+      TestDownloadRequestHandler::Parameters::WithSingleInterruption());
 
-  GURL url1 = spawned_test_server()->GetURL(
-      base::StringPrintf("rangereset?size=%d&rst_boundary=%d",
-                         GetSafeBufferChunk() * 3, GetSafeBufferChunk()));
+  DownloadItem* download = StartDownloadAndReturnItem(request_handler.url());
+  WaitForInterrupt(download);
 
-  DownloadItem* download(StartDownloadAndReturnItem(url1));
-  WaitForData(download, GetSafeBufferChunk());
-
-  ReleaseRSTAndConfirmInterruptForResume(download);
-  ConfirmFileStatusForResume(
-      download, true, GetSafeBufferChunk(), GetSafeBufferChunk() * 3,
-      base::FilePath(FILE_PATH_LITERAL("rangereset.crdownload")));
-
-  base::FilePath intermediate_path(download->GetFullPath());
+  base::FilePath intermediate_path = download->GetFullPath();
   ASSERT_FALSE(intermediate_path.empty());
-  EXPECT_TRUE(base::PathExists(intermediate_path));
+  ASSERT_TRUE(base::PathExists(intermediate_path));
 
   download->Cancel(true /* user_cancel */);
   RunAllPendingInMessageLoop(BrowserThread::FILE);
@@ -1459,81 +1338,59 @@
   EXPECT_TRUE(download->GetFullPath().empty());
 }
 
-IN_PROC_BROWSER_TEST_F(DownloadContentTest, RemoveDownload) {
+IN_PROC_BROWSER_TEST_F(DownloadContentTest, RemoveInterruptedDownload) {
   base::CommandLine::ForCurrentProcess()->AppendSwitch(
       switches::kEnableDownloadResumption);
-  ASSERT_TRUE(spawned_test_server()->Start());
+  TestDownloadRequestHandler request_handler;
+  request_handler.StartServing(
+      TestDownloadRequestHandler::Parameters::WithSingleInterruption());
 
-  // An interrupted download should remove the intermediate file when it is
-  // removed.
-  {
-    GURL url1 = spawned_test_server()->GetURL(
-        base::StringPrintf("rangereset?size=%d&rst_boundary=%d",
-                           GetSafeBufferChunk() * 3, GetSafeBufferChunk()));
+  DownloadItem* download = StartDownloadAndReturnItem(request_handler.url());
+  WaitForInterrupt(download);
 
-    DownloadItem* download(StartDownloadAndReturnItem(url1));
-    WaitForData(download, GetSafeBufferChunk());
-    ReleaseRSTAndConfirmInterruptForResume(download);
-    ConfirmFileStatusForResume(
-        download, true, GetSafeBufferChunk(), GetSafeBufferChunk() * 3,
-        base::FilePath(FILE_PATH_LITERAL("rangereset.crdownload")));
+  base::FilePath intermediate_path = download->GetFullPath();
+  ASSERT_FALSE(intermediate_path.empty());
+  ASSERT_TRUE(base::PathExists(intermediate_path));
 
-    base::FilePath intermediate_path(download->GetFullPath());
-    ASSERT_FALSE(intermediate_path.empty());
-    EXPECT_TRUE(base::PathExists(intermediate_path));
+  download->Remove();
+  RunAllPendingInMessageLoop(BrowserThread::FILE);
+  RunAllPendingInMessageLoop();
 
-    download->Remove();
-    RunAllPendingInMessageLoop(BrowserThread::FILE);
-    RunAllPendingInMessageLoop();
+  // The intermediate file should now be gone.
+  EXPECT_FALSE(base::PathExists(intermediate_path));
+}
 
-    // The intermediate file should now be gone.
-    EXPECT_FALSE(base::PathExists(intermediate_path));
-  }
-
+IN_PROC_BROWSER_TEST_F(DownloadContentTest, RemoveCompletedDownload) {
   // A completed download shouldn't delete the downloaded file when it is
   // removed.
-  {
-    // Start the second download and wait until it's done.
-    GURL url2(net::URLRequestMockHTTPJob::GetMockUrl("download-test.lib"));
-    scoped_ptr<DownloadTestObserver> completion_observer(
-        CreateWaiter(shell(), 1));
-    DownloadItem* download(StartDownloadAndReturnItem(url2));
-    completion_observer->WaitForFinished();
+  TestDownloadRequestHandler request_handler;
+  request_handler.StartServing(TestDownloadRequestHandler::Parameters());
+  scoped_ptr<DownloadTestObserver> completion_observer(
+      CreateWaiter(shell(), 1));
+  DownloadItem* download(StartDownloadAndReturnItem(request_handler.url()));
+  completion_observer->WaitForFinished();
 
-    // The target path should exist.
-    base::FilePath target_path(download->GetTargetFilePath());
-    EXPECT_TRUE(base::PathExists(target_path));
-    download->Remove();
-    RunAllPendingInMessageLoop(BrowserThread::FILE);
-    RunAllPendingInMessageLoop();
+  // The target path should exist.
+  base::FilePath target_path(download->GetTargetFilePath());
+  EXPECT_TRUE(base::PathExists(target_path));
+  download->Remove();
+  RunAllPendingInMessageLoop(BrowserThread::FILE);
+  RunAllPendingInMessageLoop();
 
-    // The file should still exist.
-    EXPECT_TRUE(base::PathExists(target_path));
-  }
+  // The file should still exist.
+  EXPECT_TRUE(base::PathExists(target_path));
 }
 
 IN_PROC_BROWSER_TEST_F(DownloadContentTest, RemoveResumingDownload) {
-  SetupEnsureNoPendingDownloads();
   base::CommandLine::ForCurrentProcess()->AppendSwitch(
       switches::kEnableDownloadResumption);
-  ASSERT_TRUE(spawned_test_server()->Start());
+  TestDownloadRequestHandler::Parameters parameters =
+      TestDownloadRequestHandler::Parameters::WithSingleInterruption();
+  TestDownloadRequestHandler request_handler;
+  request_handler.StartServing(parameters);
 
-  GURL url = spawned_test_server()->GetURL(
-      base::StringPrintf("rangereset?size=%d&rst_boundary=%d",
-                         GetSafeBufferChunk() * 3, GetSafeBufferChunk()));
-
-  MockDownloadManagerObserver dm_observer(DownloadManagerForShell(shell()));
-  EXPECT_CALL(dm_observer, OnDownloadCreated(_,_)).Times(1);
-
-  DownloadItem* download(StartDownloadAndReturnItem(url));
-  WaitForData(download, GetSafeBufferChunk());
-  ::testing::Mock::VerifyAndClearExpectations(&dm_observer);
-
-  // Tell the server to send the RST and confirm the interrupt happens.
-  ReleaseRSTAndConfirmInterruptForResume(download);
-  ConfirmFileStatusForResume(
-      download, true, GetSafeBufferChunk(), GetSafeBufferChunk() * 3,
-      base::FilePath(FILE_PATH_LITERAL("rangereset.crdownload")));
+  DownloadItem* download = StartDownloadAndReturnItem(request_handler.url());
+  WaitForInterrupt(download);
 
   base::FilePath intermediate_path(download->GetFullPath());
   ASSERT_FALSE(intermediate_path.empty());
@@ -1541,96 +1398,120 @@
 
   // Resume and remove download. We expect only a single OnDownloadCreated()
   // call, and that's for the second download created below.
+  MockDownloadManagerObserver dm_observer(DownloadManagerForShell(shell()));
   EXPECT_CALL(dm_observer, OnDownloadCreated(_,_)).Times(1);
+
+  TestRequestStartHandler request_start_handler;
+  parameters.on_start_handler = request_start_handler.GetOnStartHandler();
+  request_handler.StartServing(parameters);
+
   download->Resume();
+  request_start_handler.WaitForCallback();
+
+  // At this point, the download resumption request has been sent out, but the
+  // reponse hasn't been received yet.
   download->Remove();
 
+  request_start_handler.RespondWith(std::string(), net::OK);
+
   // The intermediate file should now be gone.
   RunAllPendingInMessageLoop(BrowserThread::FILE);
   RunAllPendingInMessageLoop();
   EXPECT_FALSE(base::PathExists(intermediate_path));
 
-  // Start the second download and wait until it's done. The test server is
-  // single threaded. The response to this download request should follow the
-  // response to the previous resumption request.
-  GURL url2(
-      spawned_test_server()->GetURL("rangereset?size=100&rst_limit=0&token=x"));
-  NavigateToURLAndWaitForDownload(shell(), url2, DownloadItem::COMPLETE);
+  parameters.ClearInjectedErrors();
+  parameters.on_start_handler.Reset();
+  request_handler.StartServing(parameters);
 
+  // Start the second download and wait until it's done. This exercises the
+  // entire downloads stack and effectively flushes all of our worker threads.
+  // We are testing whether the URL request created in the previous
+  // DownloadItem::Resume() call reulted in a new download or not.
+  NavigateToURLAndWaitForDownload(shell(), request_handler.url(),
+                                  DownloadItem::COMPLETE);
   EXPECT_TRUE(EnsureNoPendingDownloads());
 }
 
 IN_PROC_BROWSER_TEST_F(DownloadContentTest, CancelResumingDownload) {
-  SetupEnsureNoPendingDownloads();
   base::CommandLine::ForCurrentProcess()->AppendSwitch(
       switches::kEnableDownloadResumption);
-  ASSERT_TRUE(spawned_test_server()->Start());
+  TestDownloadRequestHandler::Parameters parameters =
+      TestDownloadRequestHandler::Parameters::WithSingleInterruption();
+  TestDownloadRequestHandler request_handler;
+  request_handler.StartServing(parameters);
 
-  GURL url = spawned_test_server()->GetURL(
-      base::StringPrintf("rangereset?size=%d&rst_boundary=%d",
-                         GetSafeBufferChunk() * 3, GetSafeBufferChunk()));
-
-  MockDownloadManagerObserver dm_observer(DownloadManagerForShell(shell()));
-  EXPECT_CALL(dm_observer, OnDownloadCreated(_,_)).Times(1);
-
-  DownloadItem* download(StartDownloadAndReturnItem(url));
-  WaitForData(download, GetSafeBufferChunk());
-  ::testing::Mock::VerifyAndClearExpectations(&dm_observer);
-
-  // Tell the server to send the RST and confirm the interrupt happens.
-  ReleaseRSTAndConfirmInterruptForResume(download);
-  ConfirmFileStatusForResume(
-      download, true, GetSafeBufferChunk(), GetSafeBufferChunk() * 3,
-      base::FilePath(FILE_PATH_LITERAL("rangereset.crdownload")));
+  DownloadItem* download = StartDownloadAndReturnItem(request_handler.url());
+  WaitForInterrupt(download);
 
   base::FilePath intermediate_path(download->GetFullPath());
   ASSERT_FALSE(intermediate_path.empty());
   EXPECT_TRUE(base::PathExists(intermediate_path));
 
-  // Resume and cancel download. We expect only a single OnDownloadCreated()
+  // Resume and remove download. We expect only a single OnDownloadCreated()
   // call, and that's for the second download created below.
+  MockDownloadManagerObserver dm_observer(DownloadManagerForShell(shell()));
   EXPECT_CALL(dm_observer, OnDownloadCreated(_,_)).Times(1);
+
+  TestRequestStartHandler request_start_handler;
+  parameters.on_start_handler = request_start_handler.GetOnStartHandler();
+  request_handler.StartServing(parameters);
+
   download->Resume();
-  download->Cancel(true);
+  request_start_handler.WaitForCallback();
+
+  // At this point, the download item has initiated a network request for the
+  // resumption attempt, but hasn't received a response yet.
+  download->Cancel(true /* user_cancel */);
+
+  request_start_handler.RespondWith(std::string(), net::OK);
 
   // The intermediate file should now be gone.
+  RunAllPendingInMessageLoop(BrowserThread::IO);
   RunAllPendingInMessageLoop(BrowserThread::FILE);
   RunAllPendingInMessageLoop();
   EXPECT_FALSE(base::PathExists(intermediate_path));
-  EXPECT_TRUE(download->GetFullPath().empty());
 
-  // Start the second download and wait until it's done. The test server is
-  // single threaded. The response to this download request should follow the
-  // response to the previous resumption request.
-  GURL url2(
-      spawned_test_server()->GetURL("rangereset?size=100&rst_limit=0&token=x"));
-  NavigateToURLAndWaitForDownload(shell(), url2, DownloadItem::COMPLETE);
+  parameters.ClearInjectedErrors();
+  parameters.on_start_handler.Reset();
+  request_handler.StartServing(parameters);
 
+  // Start the second download and wait until it's done. This exercises the
+  // entire downloads stack and effectively flushes all of our worker threads.
+  // We are testing whether the URL request created in the previous
+  // DownloadItem::Resume() call reulted in a new download or not.
+  NavigateToURLAndWaitForDownload(shell(), request_handler.url(),
+                                  DownloadItem::COMPLETE);
   EXPECT_TRUE(EnsureNoPendingDownloads());
 }
 
 // Check that the cookie policy is correctly updated when downloading a file
 // that redirects cross origin.
 IN_PROC_BROWSER_TEST_F(DownloadContentTest, CookiePolicy) {
-  ASSERT_TRUE(spawned_test_server()->Start());
-  net::HostPortPair host_port = spawned_test_server()->host_port_pair();
-  DCHECK_EQ(host_port.host(), std::string("127.0.0.1"));
+  net::EmbeddedTestServer origin_one;
+  net::EmbeddedTestServer origin_two;
+  ASSERT_TRUE(origin_one.Start());
+  ASSERT_TRUE(origin_two.Start());
 
   // Block third-party cookies.
   ShellNetworkDelegate::SetAcceptAllCookies(false);
 
   // |url| redirects to a different origin |download| which tries to set a
   // cookie.
-  std::string download(base::StringPrintf(
-      "http://localhost:%d/set-cookie?A=B", host_port.port()));
-  GURL url(spawned_test_server()->GetURL("server-redirect?" + download));
+  base::StringPairs cookie_header;
+  cookie_header.push_back(
+      std::make_pair(std::string("Set-Cookie"), std::string("A=B")));
+  origin_one.RegisterRequestHandler(CreateBasicResponseHandler(
+      "/foo", cookie_header, "application/octet-stream", "abcd"));
+  origin_two.RegisterRequestHandler(
+      CreateRedirectHandler("/bar", origin_one.GetURL("/foo")));
 
   // Download the file.
   SetupEnsureNoPendingDownloads();
-  scoped_ptr<DownloadUrlParameters> dl_params(
-      DownloadUrlParameters::FromWebContents(shell()->web_contents(), url));
+  scoped_ptr<DownloadUrlParameters> download_parameters(
+      DownloadUrlParameters::FromWebContents(shell()->web_contents(),
+                                             origin_two.GetURL("/bar")));
   scoped_ptr<DownloadTestObserver> observer(CreateWaiter(shell(), 1));
-  DownloadManagerForShell(shell())->DownloadUrl(dl_params.Pass());
+  DownloadManagerForShell(shell())->DownloadUrl(download_parameters.Pass());
   observer->WaitForFinished();
 
   // Get the important info from other threads and check it.
@@ -1644,7 +1525,7 @@
   // Check that the cookies were correctly set.
   EXPECT_EQ("A=B",
             content::GetCookies(shell()->web_contents()->GetBrowserContext(),
-                                GURL(download)));
+                                origin_one.GetURL("/")));
 }
 
 // A filename suggestion specified via a @download attribute should not be
@@ -1676,7 +1557,7 @@
   origin_one.RegisterRequestHandler(
       CreateRedirectHandler("/ping", origin_two.GetURL("/download")));
   origin_two.RegisterRequestHandler(CreateBasicResponseHandler(
-      "/download", "application/octet-stream", "Hello"));
+      "/download", base::StringPairs(), "application/octet-stream", "Hello"));
 
   NavigateToURLAndWaitForDownload(
       shell(), referrer_url, DownloadItem::COMPLETE);
@@ -1724,7 +1605,7 @@
   origin_two.RegisterRequestHandler(
       CreateRedirectHandler("/pong", origin_one.GetURL("/download")));
   origin_one.RegisterRequestHandler(CreateBasicResponseHandler(
-      "/download", "application/octet-stream", "Hello"));
+      "/download", base::StringPairs(), "application/octet-stream", "Hello"));
 
   NavigateToURLAndWaitForDownload(
       shell(), referrer_url, DownloadItem::COMPLETE);
@@ -1743,12 +1624,7 @@
 // The content body is empty. Make sure this case is handled properly and we
 // don't regress on http://crbug.com/320394.
 IN_PROC_BROWSER_TEST_F(DownloadContentTest, DownloadGZipWithNoContent) {
-  net::EmbeddedTestServer test_server;
-  ASSERT_TRUE(test_server.Start());
-
-  GURL url = test_server.GetURL("/empty.bin");
-  test_server.ServeFilesFromDirectory(GetTestFilePath("download", ""));
-
+  GURL url = net::URLRequestMockHTTPJob::GetMockUrl("empty.bin");
   NavigateToURLAndWaitForDownload(shell(), url, DownloadItem::COMPLETE);
   // That's it. This should work without crashing.
 }
diff --git a/content/browser/download/download_item_impl.cc b/content/browser/download/download_item_impl.cc
index 28340133..33de9d6 100644
--- a/content/browser/download/download_item_impl.cc
+++ b/content/browser/download/download_item_impl.cc
@@ -666,19 +666,12 @@
 }
 
 bool DownloadItemImpl::IsDangerous() const {
-#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_CHROMEOS)
-  // TODO(noelutz): At this point only the windows views and OSX UI supports
-  // warnings based on dangerous content.
   return (danger_type_ == DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE ||
           danger_type_ == DOWNLOAD_DANGER_TYPE_DANGEROUS_URL ||
           danger_type_ == DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT ||
           danger_type_ == DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT ||
           danger_type_ == DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST ||
           danger_type_ == DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED);
-#else
-  return (danger_type_ == DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE ||
-          danger_type_ == DOWNLOAD_DANGER_TYPE_DANGEROUS_URL);
-#endif
 }
 
 DownloadDangerType DownloadItemImpl::GetDangerType() const {
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc
index 8c87841..18a88eb4 100644
--- a/content/browser/frame_host/render_frame_host_impl.cc
+++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -1847,11 +1847,8 @@
   // Only send the message if we aren't suspended at the start of a cross-site
   // request.
   if (navigations_suspended_) {
-    // Shouldn't be possible to have a second navigation while suspended, since
-    // navigations will only be suspended during a cross-site request.  If a
-    // second navigation occurs, RenderFrameHostManager will cancel this pending
-    // RFH and create a new pending RFH.
-    DCHECK(!suspended_nav_params_.get());
+    // This may replace an existing set of params, if this is a pending RFH that
+    // is navigated twice consecutively.
     suspended_nav_params_.reset(
         new NavigationParams(common_params, start_params, request_params));
   } else {
diff --git a/content/browser/frame_host/render_frame_host_manager.cc b/content/browser/frame_host/render_frame_host_manager.cc
index 67a150e1..dab752c 100644
--- a/content/browser/frame_host/render_frame_host_manager.cc
+++ b/content/browser/frame_host/render_frame_host_manager.cc
@@ -1269,6 +1269,12 @@
     SiteInstance* new_site_instance,
     const GURL& new_effective_url,
     bool new_is_view_source_mode) const {
+  // A subframe must stay in the same BrowsingInstance as its parent.
+  // TODO(nasko): Ensure that SiteInstance swap is still triggered for subframes
+  // in the cases covered by the rest of the checks in this method.
+  if (!frame_tree_node_->IsMainFrame())
+    return false;
+
   // If new_entry already has a SiteInstance, assume it is correct.  We only
   // need to force a swap if it is in a different BrowsingInstance.
   if (new_site_instance) {
@@ -2320,17 +2326,18 @@
     return render_frame_host_.get();
   }
 
-  // If we are currently navigating cross-process, we want to get back to normal
-  // and then navigate as usual.
-  if (pending_render_frame_host_)
-    CancelPending();
-
   SiteInstance* current_instance = render_frame_host_->GetSiteInstance();
   scoped_refptr<SiteInstance> new_instance = GetSiteInstanceForNavigation(
       dest_url, source_instance, dest_instance, nullptr, transition,
       dest_is_restore, dest_is_view_source_mode);
 
-  DCHECK(!pending_render_frame_host_);
+  // If we are currently navigating cross-process to a pending RFH for a
+  // different SiteInstance, we want to get back to normal and then navigate as
+  // usual.  We will reuse the pending RFH below if it matches the destination
+  // SiteInstance.
+  if (pending_render_frame_host_ &&
+      pending_render_frame_host_->GetSiteInstance() != new_instance)
+    CancelPending();
 
   if (new_instance.get() != current_instance) {
     TRACE_EVENT_INSTANT2(
@@ -2342,10 +2349,12 @@
 
     // New SiteInstance: create a pending RFH to navigate.
 
-    CreatePendingRenderFrameHost(current_instance, new_instance.get());
+    if (!pending_render_frame_host_)
+      CreatePendingRenderFrameHost(current_instance, new_instance.get());
     DCHECK(pending_render_frame_host_);
     if (!pending_render_frame_host_)
       return nullptr;
+    DCHECK_EQ(new_instance, pending_render_frame_host_->GetSiteInstance());
 
     pending_render_frame_host_->UpdatePendingWebUI(dest_url, bindings);
     pending_render_frame_host_->CommitPendingWebUI();
@@ -2371,20 +2380,20 @@
     }
     // Otherwise, it's safe to treat this as a pending cross-process transition.
 
-    // We need to wait until the beforeunload handler has run, unless we are
-    // transferring an existing request (in which case it has already run).
-    // Suspend the new render view (i.e., don't let it send the cross-process
-    // Navigate message) until we hear back from the old renderer's
-    // beforeunload handler.  If the handler returns false, we'll have to
-    // cancel the request.
-    DCHECK(!pending_render_frame_host_->are_navigations_suspended());
     bool is_transfer = transferred_request_id != GlobalRequestID();
     if (is_transfer) {
       // We don't need to stop the old renderer or run beforeunload/unload
       // handlers, because those have already been done.
       DCHECK(cross_site_transferring_request_->request_id() ==
              transferred_request_id);
-    } else {
+    } else if (!pending_render_frame_host_->are_navigations_suspended()) {
+      // If the pending RFH hasn't already been suspended from a previous
+      // attempt to navigate it, then we need to wait for the beforeunload
+      // handler to run.  Suspend navigations in the pending RFH until we hear
+      // back from the old RFH's beforeunload handler (via OnBeforeUnloadACK or
+      // a timeout).  If the handler returns false, we'll have to cancel the
+      // request.
+      //
       // Also make sure the old render view stops, in case a load is in
       // progress.  (We don't want to do this for transfers, since it will
       // interrupt the transfer with an unexpected DidStopLoading.)
@@ -2392,10 +2401,6 @@
           render_frame_host_->GetRoutingID()));
       pending_render_frame_host_->SetNavigationsSuspended(true,
                                                           base::TimeTicks());
-      // Unless we are transferring an existing request, we should now tell the
-      // old render view to run its beforeunload handler, since it doesn't
-      // otherwise know that the cross-site request is happening.  This will
-      // trigger a call to OnBeforeUnloadACK with the reply.
       render_frame_host_->DispatchBeforeUnload(true);
     }
 
diff --git a/content/browser/frame_host/render_frame_host_manager_browsertest.cc b/content/browser/frame_host/render_frame_host_manager_browsertest.cc
index cba8284..f66fba6 100644
--- a/content/browser/frame_host/render_frame_host_manager_browsertest.cc
+++ b/content/browser/frame_host/render_frame_host_manager_browsertest.cc
@@ -2413,4 +2413,47 @@
       shell(), embedded_test_server()->GetURL("b.com", "/title3.html")));
 }
 
+// Ensure that we use the same pending RenderFrameHost if a second navigation to
+// its site occurs before it commits.  Otherwise the renderer process will have
+// two competing pending RenderFrames that both try to swap with the same
+// RenderFrameProxy.  See https://crbug.com/545900.
+IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
+                       ConsecutiveNavigationsToSite) {
+  StartEmbeddedServer();
+  EXPECT_TRUE(NavigateToURL(
+      shell(), embedded_test_server()->GetURL("a.com", "/title1.html")));
+
+  // Open a popup and navigate it to b.com to keep the b.com process alive.
+  Shell* new_shell =
+      OpenPopup(shell()->web_contents(), GURL(url::kAboutBlankURL), "popup");
+  NavigateToURL(new_shell,
+                embedded_test_server()->GetURL("b.com", "/title3.html"));
+
+  // Start a cross-site navigation to the same site but don't commit.
+  GURL cross_site_url(embedded_test_server()->GetURL("b.com", "/title1.html"));
+  NavigationStallDelegate stall_delegate(cross_site_url);
+  ResourceDispatcherHost::Get()->SetDelegate(&stall_delegate);
+  shell()->LoadURL(cross_site_url);
+
+  WebContentsImpl* web_contents = static_cast<WebContentsImpl*>(
+      shell()->web_contents());
+  RenderFrameHostImpl* pending_rfh =
+      web_contents->GetRenderManagerForTesting()->pending_frame_host();
+  ASSERT_TRUE(pending_rfh);
+
+  // Navigate to the same new site and verify that we commit in the same RFH.
+  GURL cross_site_url2(embedded_test_server()->GetURL("b.com", "/title2.html"));
+  TestNavigationObserver navigation_observer(web_contents, 1);
+  shell()->LoadURL(cross_site_url2);
+  EXPECT_EQ(pending_rfh,
+            web_contents->GetRenderManagerForTesting()->pending_frame_host());
+  navigation_observer.Wait();
+  EXPECT_EQ(cross_site_url2, web_contents->GetLastCommittedURL());
+  EXPECT_EQ(pending_rfh, web_contents->GetMainFrame());
+  EXPECT_FALSE(
+      web_contents->GetRenderManagerForTesting()->pending_frame_host());
+
+  ResourceDispatcherHost::Get()->SetDelegate(nullptr);
+}
+
 }  // namespace content
diff --git a/content/browser/frame_host/render_frame_message_filter.cc b/content/browser/frame_host/render_frame_message_filter.cc
index b13d6d78..462f219 100644
--- a/content/browser/frame_host/render_frame_message_filter.cc
+++ b/content/browser/frame_host/render_frame_message_filter.cc
@@ -299,6 +299,8 @@
     IPC_MESSAGE_HANDLER(FrameHostMsg_CookiesEnabled, OnCookiesEnabled)
     IPC_MESSAGE_HANDLER(FrameHostMsg_Are3DAPIsBlocked, OnAre3DAPIsBlocked)
     IPC_MESSAGE_HANDLER(FrameHostMsg_DidLose3DContext, OnDidLose3DContext)
+    IPC_MESSAGE_HANDLER_GENERIC(FrameHostMsg_RenderProcessGone,
+                                OnRenderProcessGone())
 #if defined(ENABLE_PLUGINS)
     IPC_MESSAGE_HANDLER_DELAY_REPLY(FrameHostMsg_GetPlugins, OnGetPlugins)
     IPC_MESSAGE_HANDLER(FrameHostMsg_GetPluginInfo, OnGetPluginInfo)
@@ -468,6 +470,14 @@
       top_origin_url, guilt);
 }
 
+void RenderFrameMessageFilter::OnRenderProcessGone() {
+  // FrameHostMessage_RenderProcessGone is a synthetic IPC message used by
+  // RenderProcessHostImpl to clean things up after a crash (it's injected
+  // downstream of this filter). Allowing it to proceed would enable a renderer
+  // to fake its own death; instead, actually kill the renderer.
+  bad_message::ReceivedBadMessage(
+      this, bad_message::RFMF_RENDERER_FAKED_ITS_OWN_DEATH);
+}
 
 #if defined(ENABLE_PLUGINS)
 
diff --git a/content/browser/frame_host/render_frame_message_filter.h b/content/browser/frame_host/render_frame_message_filter.h
index 43dc78b5a..3642128 100644
--- a/content/browser/frame_host/render_frame_message_filter.h
+++ b/content/browser/frame_host/render_frame_message_filter.h
@@ -99,6 +99,8 @@
                           ThreeDAPIType context_type,
                           int arb_robustness_status_code);
 
+  void OnRenderProcessGone();
+
 #if defined(ENABLE_PLUGINS)
   void OnGetPlugins(bool refresh, IPC::Message* reply_msg);
   void GetPluginsCallback(IPC::Message* reply_msg,
diff --git a/content/browser/renderer_host/render_message_filter_browsertest.cc b/content/browser/frame_host/render_frame_message_filter_browsertest.cc
similarity index 76%
rename from content/browser/renderer_host/render_message_filter_browsertest.cc
rename to content/browser/frame_host/render_frame_message_filter_browsertest.cc
index 3f05b5f..96eb9c1 100644
--- a/content/browser/renderer_host/render_message_filter_browsertest.cc
+++ b/content/browser/frame_host/render_frame_message_filter_browsertest.cc
@@ -7,6 +7,8 @@
 #include "base/basictypes.h"
 #include "base/command_line.h"
 #include "base/files/file_path.h"
+#include "base/test/histogram_tester.h"
+#include "content/browser/bad_message.h"
 #include "content/browser/frame_host/frame_tree.h"
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/common/frame_messages.h"
@@ -21,6 +23,7 @@
 #include "ipc/ipc_security_test_util.h"
 #include "net/dns/mock_host_resolver.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
+#include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace content {
@@ -36,11 +39,11 @@
 
 }  // namespace
 
-using RenderMessageFilterBrowserTest = ContentBrowserTest;
+using RenderFrameMessageFilterBrowserTest = ContentBrowserTest;
 
 // Exercises basic cookie operations via javascript, including an http page
 // interacting with secure cookies.
-IN_PROC_BROWSER_TEST_F(RenderMessageFilterBrowserTest, Cookies) {
+IN_PROC_BROWSER_TEST_F(RenderFrameMessageFilterBrowserTest, Cookies) {
   host_resolver()->AddRule("*", "127.0.0.1");
   ASSERT_TRUE(embedded_test_server()->Start());
   SetupCrossSiteRedirector(embedded_test_server());
@@ -49,8 +52,8 @@
   https_server.ServeFilesFromSourceDirectory("content/test/data");
   ASSERT_TRUE(https_server.Start());
 
-  // The server sends a HttpOnly cookie. The RenderMessageFilter should never
-  // allow this to be sent to any renderer process.
+  // The server sends a HttpOnly cookie. The RenderFrameMessageFilter should
+  // never allow this to be sent to any renderer process.
   GURL https_url = https_server.GetURL("/set-cookie?notforjs=1;HttpOnly");
   GURL http_url = embedded_test_server()->GetURL("/frame_with_load_event.html");
 
@@ -100,9 +103,10 @@
   EXPECT_EQ("B=2; D=4", GetCookieFromJS(web_contents_http->GetMainFrame()));
 }
 
-// The RenderMessageFilter will kill processes when they access the cookies of
-// sites other than the site the process is dedicated to, under site isolation.
-IN_PROC_BROWSER_TEST_F(RenderMessageFilterBrowserTest,
+// The RenderFrameMessageFilter will kill processes when they access the cookies
+// of sites other than the site the process is dedicated to, under site
+// isolation.
+IN_PROC_BROWSER_TEST_F(RenderFrameMessageFilterBrowserTest,
                        CrossSiteCookieSecurityEnforcement) {
   // The code under test is only active under site isolation.
   if (!AreAllSitesIsolatedForTesting()) {
@@ -173,4 +177,36 @@
       v.DepictFrameTree(tab->GetFrameTree()->root()));
 }
 
+// FrameHostMsg_RenderProcessGone is a synthetic message that's really an
+// implementation detail of RenderProcessHostImpl's crash recovery. It should be
+// ignored if it arrives over the IPC channel.
+IN_PROC_BROWSER_TEST_F(RenderFrameMessageFilterBrowserTest, RenderProcessGone) {
+  GURL web_url("http://foo.com/simple_page.html");
+  NavigateToURL(shell(), web_url);
+  RenderFrameHost* web_rfh = shell()->web_contents()->GetMainFrame();
+
+  base::HistogramTester uma;
+
+  ASSERT_TRUE(web_rfh->IsRenderFrameLive());
+  RenderProcessHostWatcher web_process_killed(
+      web_rfh->GetProcess(), RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
+  IPC::IpcSecurityTestUtil::PwnMessageReceived(
+      web_rfh->GetProcess()->GetChannel(),
+      FrameHostMsg_RenderProcessGone(
+          web_rfh->GetRoutingID(), base::TERMINATION_STATUS_NORMAL_TERMINATION,
+          0));
+
+  EXPECT_THAT(uma.GetAllSamples("Stability.BadMessageTerminated.Content"),
+              testing::ElementsAre(base::Bucket(
+                  bad_message::RFMF_RENDERER_FAKED_ITS_OWN_DEATH, 1)));
+
+  // If the message had gone through, we'd have marked the RFH as dead but
+  // left the RPH and its connection alive, and the Wait below would hang.
+  web_process_killed.Wait();
+
+  ASSERT_FALSE(web_rfh->GetProcess()->HasConnection());
+  ASSERT_FALSE(web_rfh->IsRenderFrameLive());
+  ASSERT_FALSE(web_process_killed.did_exit_normally());
+}
+
 }  // namespace content
diff --git a/content/browser/frame_host/render_frame_proxy_host.cc b/content/browser/frame_host/render_frame_proxy_host.cc
index c921e04..1f0c182 100644
--- a/content/browser/frame_host/render_frame_proxy_host.cc
+++ b/content/browser/frame_host/render_frame_proxy_host.cc
@@ -146,6 +146,7 @@
     IPC_MESSAGE_HANDLER(FrameHostMsg_OpenURL, OnOpenURL)
     IPC_MESSAGE_HANDLER(FrameHostMsg_RouteMessageEvent, OnRouteMessageEvent)
     IPC_MESSAGE_HANDLER(FrameHostMsg_DidChangeOpener, OnDidChangeOpener)
+    IPC_MESSAGE_HANDLER(FrameHostMsg_AdvanceFocus, OnAdvanceFocus)
     IPC_MESSAGE_UNHANDLED(handled = false)
   IPC_END_MESSAGE_MAP()
   return handled;
@@ -325,4 +326,29 @@
                                                       GetSiteInstance());
 }
 
+void RenderFrameProxyHost::OnAdvanceFocus(blink::WebFocusType type,
+                                          int32_t source_routing_id) {
+  RenderFrameHostImpl* target_rfh =
+      frame_tree_node_->render_manager()->current_frame_host();
+
+  // Translate the source RenderFrameHost in this process to its equivalent
+  // RenderFrameProxyHost in the target process.  This is needed for continuing
+  // the focus traversal from correct place in a parent frame after one of its
+  // child frames finishes its traversal.
+  RenderFrameHostImpl* source_rfh =
+      RenderFrameHostImpl::FromID(GetProcess()->GetID(), source_routing_id);
+  int32_t source_proxy_routing_id = MSG_ROUTING_NONE;
+  if (source_rfh) {
+    RenderFrameProxyHost* source_proxy =
+        source_rfh->frame_tree_node()
+            ->render_manager()
+            ->GetRenderFrameProxyHost(target_rfh->GetSiteInstance());
+    if (source_proxy)
+      source_proxy_routing_id = source_proxy->GetRoutingID();
+  }
+
+  target_rfh->Send(new FrameMsg_AdvanceFocus(target_rfh->GetRoutingID(), type,
+                                             source_proxy_routing_id));
+}
+
 }  // namespace content
diff --git a/content/browser/frame_host/render_frame_proxy_host.h b/content/browser/frame_host/render_frame_proxy_host.h
index fd5fc6c..c8b0db0 100644
--- a/content/browser/frame_host/render_frame_proxy_host.h
+++ b/content/browser/frame_host/render_frame_proxy_host.h
@@ -10,6 +10,7 @@
 #include "content/browser/site_instance_impl.h"
 #include "ipc/ipc_listener.h"
 #include "ipc/ipc_sender.h"
+#include "third_party/WebKit/public/platform/WebFocusType.h"
 
 struct FrameMsg_PostMessage_Params;
 
@@ -129,6 +130,7 @@
   void OnOpenURL(const FrameHostMsg_OpenURL_Params& params);
   void OnRouteMessageEvent(const FrameMsg_PostMessage_Params& params);
   void OnDidChangeOpener(int32 opener_routing_id);
+  void OnAdvanceFocus(blink::WebFocusType type, int32_t source_routing_id);
 
   // This RenderFrameProxyHost's routing id.
   int routing_id_;
diff --git a/content/browser/indexed_db/indexed_db_browsertest.cc b/content/browser/indexed_db/indexed_db_browsertest.cc
index 0428d35..bafe726 100644
--- a/content/browser/indexed_db/indexed_db_browsertest.cc
+++ b/content/browser/indexed_db/indexed_db_browsertest.cc
@@ -778,7 +778,15 @@
   exit(0);
 }
 
-IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, VersionChangeCrashResilience) {
+// Fails to cleanup GPU processes on swarming.
+// http://crbug.com/552543
+#if defined(OS_WIN)
+#define MAYBE_VersionChangeCrashResilience DISABLED_VersionChangeCrashResilience
+#else
+#define MAYBE_VersionChangeCrashResilience VersionChangeCrashResilience
+#endif
+IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest,
+                       MAYBE_VersionChangeCrashResilience) {
   NavigateAndWaitForTitle(shell(), "version_change_crash.html", "#part3",
                           "pass - part3 - rolled back");
 }
diff --git a/content/browser/mojo/OWNERS b/content/browser/mojo/OWNERS
new file mode 100644
index 0000000..570120f
--- /dev/null
+++ b/content/browser/mojo/OWNERS
@@ -0,0 +1,13 @@
+# Changes to the renderer capability filter require a security review to avoid
+# exposing new sandbox escapes and undesirable services.
+per-file renderer_capability_filter.cc=set noparent
+per-file renderer_capability_filter.cc=dcheng@chromium.org
+per-file renderer_capability_filter.cc=inferno@chromium.org
+per-file renderer_capability_filter.cc=jln@chromium.org
+per-file renderer_capability_filter.cc=jschuh@chromium.org
+per-file renderer_capability_filter.cc=kenrb@chromium.org
+per-file renderer_capability_filter.cc=mkwst@chromium.org
+per-file renderer_capability_filter.cc=nasko@chromium.org
+per-file renderer_capability_filter.cc=palmer@chromium.org
+per-file renderer_capability_filter.cc=tsepez@chromium.org
+per-file renderer_capability_filter.cc=wfh@chromium.org
diff --git a/content/browser/mojo/mojo_shell_client_host.cc b/content/browser/mojo/mojo_shell_client_host.cc
index 8616a37..53be44dd1 100644
--- a/content/browser/mojo/mojo_shell_client_host.cc
+++ b/content/browser/mojo/mojo_shell_client_host.cc
@@ -4,7 +4,6 @@
 
 #include "base/strings/stringprintf.h"
 #include "base/thread_task_runner_handle.h"
-#include "components/mus/public/interfaces/gpu.mojom.h"
 #include "content/browser/mojo/mojo_shell_client_host.h"
 #include "content/common/mojo/mojo_messages.h"
 #include "content/public/browser/render_process_host.h"
@@ -104,14 +103,10 @@
   std::string url =
       base::StringPrintf("exe:chrome_renderer%d", child_process_id);
 
-  mojo::CapabilityFilterPtr filter(mojo::CapabilityFilter::New());
-  mojo::Array<mojo::String> window_manager_interfaces;
-  window_manager_interfaces.push_back(mus::mojom::Gpu::Name_);
-  filter->filter.insert("mojo:mus", window_manager_interfaces.Pass());
   application_manager->CreateInstanceForHandle(
       mojo::ScopedHandle(mojo::Handle(handle.release().value())),
       url,
-      filter.Pass());
+      CreateCapabilityFilterForRenderer());
 
   // Send the other end to the child via Chrome IPC.
   base::PlatformFile client_file = PlatformFileFromScopedPlatformHandle(
diff --git a/content/browser/mojo/mojo_shell_client_host.h b/content/browser/mojo/mojo_shell_client_host.h
index c59924f..53f5a1e86 100644
--- a/content/browser/mojo/mojo_shell_client_host.h
+++ b/content/browser/mojo/mojo_shell_client_host.h
@@ -8,6 +8,7 @@
 #include <string>
 
 #include "base/process/process_handle.h"
+#include "mojo/application/public/interfaces/shell.mojom.h"
 
 namespace content {
 
@@ -30,6 +31,13 @@
 void SendExternalMojoShellHandleToChild(base::ProcessHandle process_handle,
                                         RenderProcessHost* render_process_host);
 
+// Constructs a Capability Filter for the renderer's application instance in the
+// external shell. This contains the restrictions imposed on what applications
+// and interfaces the renderer can see. The implementation lives in
+// renderer_capability_filter.cc so that it can be subject to specific security
+// review.
+mojo::CapabilityFilterPtr CreateCapabilityFilterForRenderer();
+
 }  // namespace content
 
 #endif  // CONTENT_BROWSER_MOJO_MOJO_SHELL_CLIENT_HOST_H_
diff --git a/content/browser/mojo/renderer_capability_filter.cc b/content/browser/mojo/renderer_capability_filter.cc
new file mode 100644
index 0000000..871e692
--- /dev/null
+++ b/content/browser/mojo/renderer_capability_filter.cc
@@ -0,0 +1,20 @@
+// 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.
+
+#include "components/mus/public/interfaces/gpu.mojom.h"
+#include "content/browser/mojo/mojo_shell_client_host.h"
+
+namespace content {
+
+mojo::CapabilityFilterPtr CreateCapabilityFilterForRenderer() {
+  // See https://goo.gl/gkBtCR for a description of what this is and what to
+  // think about when changing it.
+  mojo::CapabilityFilterPtr filter(mojo::CapabilityFilter::New());
+  mojo::Array<mojo::String> window_manager_interfaces;
+  window_manager_interfaces.push_back(mus::mojom::Gpu::Name_);
+  filter->filter.insert("mojo:mus", window_manager_interfaces.Pass());
+  return filter;
+}
+
+}  // namespace content
diff --git a/content/browser/net/browser_online_state_observer.cc b/content/browser/net/browser_online_state_observer.cc
index 23071d6..9b457f9b 100644
--- a/content/browser/net/browser_online_state_observer.cc
+++ b/content/browser/net/browser_online_state_observer.cc
@@ -6,11 +6,15 @@
 
 #include "content/common/view_messages.h"
 #include "content/browser/renderer_host/render_process_host_impl.h"
+#include "content/public/browser/notification_service.h"
+#include "content/public/browser/notification_types.h"
 
 namespace content {
 
 BrowserOnlineStateObserver::BrowserOnlineStateObserver() {
   net::NetworkChangeNotifier::AddMaxBandwidthObserver(this);
+  registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CREATED,
+                 content::NotificationService::AllSources());
 }
 
 BrowserOnlineStateObserver::~BrowserOnlineStateObserver() {
@@ -27,4 +31,20 @@
   }
 }
 
+void BrowserOnlineStateObserver::Observe(
+    int type,
+    const content::NotificationSource& source,
+    const content::NotificationDetails& details) {
+  DCHECK_EQ(NOTIFICATION_RENDERER_PROCESS_CREATED, type);
+
+  content::RenderProcessHost* rph =
+      content::Source<content::RenderProcessHost>(source).ptr();
+  double max_bandwidth_mbps;
+  net::NetworkChangeNotifier::ConnectionType connection_type;
+  net::NetworkChangeNotifier::GetMaxBandwidthAndConnectionType(
+      &max_bandwidth_mbps, &connection_type);
+  rph->Send(new ViewMsg_NetworkConnectionChanged(connection_type,
+                                                 max_bandwidth_mbps));
+}
+
 }  // namespace content
diff --git a/content/browser/net/browser_online_state_observer.h b/content/browser/net/browser_online_state_observer.h
index b722eff..3a7867e 100644
--- a/content/browser/net/browser_online_state_observer.h
+++ b/content/browser/net/browser_online_state_observer.h
@@ -6,6 +6,8 @@
 #define CONTENT_BROWSER_NET_BROWSER_ONLINE_STATE_OBSERVER_H_
 
 #include "base/basictypes.h"
+#include "content/public/browser/notification_observer.h"
+#include "content/public/browser/notification_registrar.h"
 #include "net/base/network_change_notifier.h"
 
 namespace content {
@@ -13,17 +15,25 @@
 // Listens for changes to the online state and manages sending
 // updates to each RenderProcess via RenderProcessHost IPC.
 class BrowserOnlineStateObserver
-    : public net::NetworkChangeNotifier::MaxBandwidthObserver {
+    : public net::NetworkChangeNotifier::MaxBandwidthObserver,
+      public content::NotificationObserver {
  public:
   BrowserOnlineStateObserver();
   ~BrowserOnlineStateObserver() override;
 
-  // MaxBandwidthObserver implementation.
+  // MaxBandwidthObserver implementation
   void OnMaxBandwidthChanged(
       double max_bandwidth_mbps,
       net::NetworkChangeNotifier::ConnectionType type) override;
 
+  // NotificationObserver implementation
+  void Observe(int type,
+               const content::NotificationSource& source,
+               const content::NotificationDetails& details) override;
+
  private:
+  content::NotificationRegistrar registrar_;
+
   DISALLOW_COPY_AND_ASSIGN(BrowserOnlineStateObserver);
 };
 
diff --git a/content/browser/net_info_browsertest.cc b/content/browser/net_info_browsertest.cc
index 5701787b..bfc4d813 100644
--- a/content/browser/net_info_browsertest.cc
+++ b/content/browser/net_info_browsertest.cc
@@ -76,6 +76,18 @@
   }
 };
 
+// Make sure the type is correct when the page is first opened.
+IN_PROC_BROWSER_TEST_F(NetInfoBrowserTest, VerifyNetworkStateInitialized) {
+  SetConnectionType(net::NetworkChangeNotifier::CONNECTION_ETHERNET,
+                    net::NetworkChangeNotifier::SUBTYPE_GIGABIT_ETHERNET);
+  NavigateToURL(shell(), content::GetTestUrl("", "net_info.html"));
+  EXPECT_TRUE(RunScriptExtractBool("getOnLine()"));
+  EXPECT_EQ("ethernet", RunScriptExtractString("getType()"));
+  EXPECT_EQ(net::NetworkChangeNotifier::GetMaxBandwidthForConnectionSubtype(
+                net::NetworkChangeNotifier::SUBTYPE_GIGABIT_ETHERNET),
+            RunScriptExtractDouble("getDownlinkMax()"));
+}
+
 // Make sure that type changes in the browser make their way to
 // navigator.connection.type.
 IN_PROC_BROWSER_TEST_F(NetInfoBrowserTest, NetworkChangePlumbsToNavigator) {
@@ -110,4 +122,25 @@
   EXPECT_TRUE(RunScriptExtractBool("getOnLine()"));
 }
 
+// Creating a new render view shouldn't reinitialize Blink's
+// NetworkStateNotifier. See https://crbug.com/535081.
+IN_PROC_BROWSER_TEST_F(NetInfoBrowserTest, TwoRenderViewsInOneProcess) {
+  SetConnectionType(net::NetworkChangeNotifier::CONNECTION_ETHERNET,
+                    net::NetworkChangeNotifier::SUBTYPE_GIGABIT_ETHERNET);
+  NavigateToURL(shell(), content::GetTestUrl("", "net_info.html"));
+  EXPECT_TRUE(RunScriptExtractBool("getOnLine()"));
+
+  SetConnectionType(net::NetworkChangeNotifier::CONNECTION_NONE,
+                    net::NetworkChangeNotifier::SUBTYPE_NONE);
+  EXPECT_FALSE(RunScriptExtractBool("getOnLine()"));
+
+  // Open the same page in a new window on the same process.
+  EXPECT_TRUE(
+      ExecuteScript(shell()->web_contents(), "window.open(\"net_info.html\")"));
+
+  // The network state should not have reinitialized to what it was when opening
+  // the first window (online).
+  EXPECT_FALSE(RunScriptExtractBool("getOnLine()"));
+}
+
 }  // namespace content
diff --git a/content/browser/power_save_blocker_impl.h b/content/browser/power_save_blocker_impl.h
index a304226..76af7253 100644
--- a/content/browser/power_save_blocker_impl.h
+++ b/content/browser/power_save_blocker_impl.h
@@ -43,6 +43,13 @@
   // };
   scoped_refptr<Delegate> delegate_;
 
+#if defined(USE_X11)
+  // Since display sleep prevention also implies system suspend prevention, for
+  // the Linux FreeDesktop API case, there needs to be a second delegate to
+  // block system suspend when screen saver / display sleep is blocked.
+  scoped_refptr<Delegate> freedesktop_suspend_delegate_;
+#endif
+
   DISALLOW_COPY_AND_ASSIGN(PowerSaveBlockerImpl);
 };
 
diff --git a/content/browser/power_save_blocker_x11.cc b/content/browser/power_save_blocker_x11.cc
index 4783063..d5c79f43 100644
--- a/content/browser/power_save_blocker_x11.cc
+++ b/content/browser/power_save_blocker_x11.cc
@@ -52,12 +52,17 @@
 const char kGnomeAPIInterfaceName[] = "org.gnome.SessionManager";
 const char kGnomeAPIObjectPath[] = "/org/gnome/SessionManager";
 
-const char kFreeDesktopAPIServiceName[] = "org.freedesktop.PowerManagement";
-const char kFreeDesktopAPIInterfaceName[] =
+const char kFreeDesktopAPIPowerServiceName[] =
+    "org.freedesktop.PowerManagement";
+const char kFreeDesktopAPIPowerInterfaceName[] =
     "org.freedesktop.PowerManagement.Inhibit";
-const char kFreeDesktopAPIObjectPath[] =
+const char kFreeDesktopAPIPowerObjectPath[] =
     "/org/freedesktop/PowerManagement/Inhibit";
 
+const char kFreeDesktopAPIScreenServiceName[] = "org.freedesktop.ScreenSaver";
+const char kFreeDesktopAPIScreenInterfaceName[] = "org.freedesktop.ScreenSaver";
+const char kFreeDesktopAPIScreenObjectPath[] = "/org/freedesktop/ScreenSaver";
+
 }  // namespace
 
 namespace content {
@@ -66,7 +71,9 @@
     : public base::RefCountedThreadSafe<PowerSaveBlockerImpl::Delegate> {
  public:
   // Picks an appropriate D-Bus API to use based on the desktop environment.
-  Delegate(PowerSaveBlockerType type, const std::string& description);
+  Delegate(PowerSaveBlockerType type,
+           const std::string& description,
+           bool freedesktop_only);
 
   // Post a task to initialize the delegate on the UI thread, which will itself
   // then post a task to apply the power save block on the FILE thread.
@@ -109,6 +116,7 @@
 
   const PowerSaveBlockerType type_;
   const std::string description_;
+  const bool freedesktop_only_;
 
   // Initially, we post a message to the UI thread to select an API. When it
   // finishes, it will post a message to the FILE thread to perform the actual
@@ -138,9 +146,11 @@
 };
 
 PowerSaveBlockerImpl::Delegate::Delegate(PowerSaveBlockerType type,
-                                         const std::string& description)
+                                         const std::string& description,
+                                         bool freedesktop_only)
     : type_(type),
       description_(description),
+      freedesktop_only_(freedesktop_only),
       api_(NO_API),
       enqueue_apply_(false),
       inhibit_cookie_(0) {
@@ -176,7 +186,9 @@
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   base::AutoLock lock(lock_);
   api_ = SelectAPI();
-  if (enqueue_apply_ && api_ != NO_API) {
+  bool api_matches =
+      freedesktop_only_ ? api_ == FREEDESKTOP_API : api_ != NO_API;
+  if (enqueue_apply_ && api_matches) {
     // The thread we use here becomes the origin and D-Bus thread for the D-Bus
     // library, so we need to use the same thread above for RemoveBlock(). It
     // must be a thread that allows I/O operations, so we use the FILE thread.
@@ -235,11 +247,22 @@
       }
       break;
     case FREEDESKTOP_API:
-      object_proxy = bus_->GetObjectProxy(
-          kFreeDesktopAPIServiceName,
-          dbus::ObjectPath(kFreeDesktopAPIObjectPath));
-      method_call.reset(
-          new dbus::MethodCall(kFreeDesktopAPIInterfaceName, "Inhibit"));
+      switch (type_) {
+        case kPowerSaveBlockPreventDisplaySleep:
+          object_proxy = bus_->GetObjectProxy(
+              kFreeDesktopAPIScreenServiceName,
+              dbus::ObjectPath(kFreeDesktopAPIScreenObjectPath));
+          method_call.reset(new dbus::MethodCall(
+              kFreeDesktopAPIScreenInterfaceName, "Inhibit"));
+          break;
+        case kPowerSaveBlockPreventAppSuspension:
+          object_proxy = bus_->GetObjectProxy(
+              kFreeDesktopAPIPowerServiceName,
+              dbus::ObjectPath(kFreeDesktopAPIPowerObjectPath));
+          method_call.reset(new dbus::MethodCall(
+              kFreeDesktopAPIPowerInterfaceName, "Inhibit"));
+          break;
+      }
       message_writer.reset(new dbus::MessageWriter(method_call.get()));
       // The arguments of the method are:
       //     app_id:        The application identifier
@@ -311,11 +334,22 @@
           new dbus::MethodCall(kGnomeAPIInterfaceName, "Uninhibit"));
       break;
     case FREEDESKTOP_API:
-      object_proxy = bus_->GetObjectProxy(
-          kFreeDesktopAPIServiceName,
-          dbus::ObjectPath(kFreeDesktopAPIObjectPath));
-      method_call.reset(
-          new dbus::MethodCall(kFreeDesktopAPIInterfaceName, "UnInhibit"));
+      switch (type_) {
+        case kPowerSaveBlockPreventDisplaySleep:
+          object_proxy = bus_->GetObjectProxy(
+              kFreeDesktopAPIScreenServiceName,
+              dbus::ObjectPath(kFreeDesktopAPIScreenObjectPath));
+          method_call.reset(new dbus::MethodCall(
+              kFreeDesktopAPIScreenInterfaceName, "UnInhibit"));
+          break;
+        case kPowerSaveBlockPreventAppSuspension:
+          object_proxy = bus_->GetObjectProxy(
+              kFreeDesktopAPIPowerServiceName,
+              dbus::ObjectPath(kFreeDesktopAPIPowerObjectPath));
+          method_call.reset(new dbus::MethodCall(
+              kFreeDesktopAPIPowerInterfaceName, "UnInhibit"));
+          break;
+      }
       break;
   }
 
@@ -383,12 +417,21 @@
 PowerSaveBlockerImpl::PowerSaveBlockerImpl(PowerSaveBlockerType type,
                                            Reason reason,
                                            const std::string& description)
-    : delegate_(new Delegate(type, description)) {
+    : delegate_(new Delegate(type, description, false /* freedesktop_only */)) {
   delegate_->Init();
+
+  if (type == kPowerSaveBlockPreventDisplaySleep) {
+    freedesktop_suspend_delegate_ =
+        new Delegate(kPowerSaveBlockPreventAppSuspension, description,
+                     true /* freedesktop_only */);
+    freedesktop_suspend_delegate_->Init();
+  }
 }
 
 PowerSaveBlockerImpl::~PowerSaveBlockerImpl() {
   delegate_->CleanUp();
+  if (freedesktop_suspend_delegate_)
+    freedesktop_suspend_delegate_->CleanUp();
 }
 
 }  // namespace content
diff --git a/content/browser/renderer_host/media/video_capture_gpu_jpeg_decoder.cc b/content/browser/renderer_host/media/video_capture_gpu_jpeg_decoder.cc
index 4e88200..a370ccf5 100644
--- a/content/browser/renderer_host/media/video_capture_gpu_jpeg_decoder.cc
+++ b/content/browser/renderer_host/media/video_capture_gpu_jpeg_decoder.cc
@@ -4,6 +4,8 @@
 
 #include "content/browser/renderer_host/media/video_capture_gpu_jpeg_decoder.h"
 
+#include <utility>
+
 #include "base/bind.h"
 #include "base/command_line.h"
 #include "base/logging.h"
@@ -210,7 +212,7 @@
       BrowserGpuChannelHostFactory::instance()->GetGpuChannel());
   task_runner->PostTask(
       FROM_HERE, base::Bind(&VideoCaptureGpuJpegDecoder::FinishInitialization,
-                            weak_this, base::Passed(&gpu_channel_host)));
+                            weak_this, std::move(gpu_channel_host)));
 }
 
 void VideoCaptureGpuJpegDecoder::FinishInitialization(
@@ -220,7 +222,7 @@
   if (!gpu_channel_host) {
     LOG(ERROR) << "Failed to establish GPU channel for JPEG decoder";
   } else if (gpu_channel_host->gpu_info().jpeg_decode_accelerator_supported) {
-    gpu_channel_host_ = gpu_channel_host.Pass();
+    gpu_channel_host_ = std::move(gpu_channel_host);
     decoder_ = gpu_channel_host_->CreateJpegDecoder(this);
   }
   decoder_status_ = decoder_ ? INIT_PASSED : FAILED;
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index 4c2413e3..60b94257 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -1385,7 +1385,6 @@
     switches::kEnablePreciseMemoryInfo,
     switches::kEnablePreferCompositingToLCDText,
     switches::kEnablePrefixedEncryptedMedia,
-    switches::kEnablePushMessagePayload,
     switches::kEnableRGBA4444Textures,
     switches::kEnableRendererMojoChannel,
     switches::kEnableSkiaBenchmarking,
diff --git a/content/browser/renderer_host/render_view_host_impl.cc b/content/browser/renderer_host/render_view_host_impl.cc
index d33bc94..b772300a 100644
--- a/content/browser/renderer_host/render_view_host_impl.cc
+++ b/content/browser/renderer_host/render_view_host_impl.cc
@@ -74,7 +74,6 @@
 #include "content/public/common/url_utils.h"
 #include "net/base/filename_util.h"
 #include "net/base/net_util.h"
-#include "net/base/network_change_notifier.h"
 #include "net/url_request/url_request_context_getter.h"
 #include "storage/browser/fileapi/isolated_context.h"
 #include "third_party/skia/include/core/SkBitmap.h"
@@ -506,11 +505,6 @@
     prefs.javascript_enabled = true;
   }
 
-  net::NetworkChangeNotifier::GetMaxBandwidthAndConnectionType(
-      &prefs.net_info_max_bandwidth_mbps, &prefs.net_info_connection_type);
-  prefs.is_online = prefs.net_info_connection_type !=
-                    net::NetworkChangeNotifier::CONNECTION_NONE;
-
   prefs.number_of_cpu_cores = base::SysInfo::NumberOfProcessors();
 
   prefs.viewport_enabled =
diff --git a/content/browser/renderer_host/render_widget_host_view_mus.cc b/content/browser/renderer_host/render_widget_host_view_mus.cc
index bc0ae25..76f405a 100644
--- a/content/browser/renderer_host/render_widget_host_view_mus.cc
+++ b/content/browser/renderer_host/render_widget_host_view_mus.cc
@@ -12,6 +12,7 @@
 #include "content/common/render_widget_window_tree_client_factory.mojom.h"
 #include "content/public/common/mojo_shell_connection.h"
 #include "mojo/application/public/cpp/application_impl.h"
+#include "ui/aura/window.h"
 
 namespace blink {
 struct WebScreenInfo;
@@ -61,18 +62,15 @@
 }
 
 void RenderWidgetHostViewMus::SetSize(const gfx::Size& size) {
-  size_ = size;
-  gfx::Rect bounds = window_->window()->bounds();
-  // TODO(fsamuel): figure out position.
-  bounds.set_x(10);
-  bounds.set_y(150);
-  bounds.set_size(size);
+  platform_view_->SetSize(size);
+  gfx::Rect bounds = platform_view_->GetNativeView()->GetBoundsInRootWindow();
   window_->window()->SetBounds(bounds);
-  host_->WasResized();
 }
 
 void RenderWidgetHostViewMus::SetBounds(const gfx::Rect& rect) {
-  SetSize(rect.size());
+  platform_view_->SetBounds(rect);
+  gfx::Rect bounds = platform_view_->GetNativeView()->GetBoundsInRootWindow();
+  window_->window()->SetBounds(bounds);
 }
 
 void RenderWidgetHostViewMus::Focus() {
@@ -91,7 +89,7 @@
 }
 
 gfx::Rect RenderWidgetHostViewMus::GetViewBounds() const {
-  return gfx::Rect(size_);
+  return platform_view_->GetViewBounds();
 }
 
 gfx::Vector2dF RenderWidgetHostViewMus::GetLastScrollOffset() const {
@@ -142,7 +140,7 @@
 }
 
 gfx::NativeView RenderWidgetHostViewMus::GetNativeView() const {
-  return gfx::NativeView();
+  return platform_view_->GetNativeView();
 }
 
 gfx::NativeViewId RenderWidgetHostViewMus::GetNativeViewId() const {
@@ -244,7 +242,7 @@
 }
 
 gfx::Rect RenderWidgetHostViewMus::GetBoundsInRootWindow() {
-  return GetViewBounds();
+  return platform_view_->GetBoundsInRootWindow();
 }
 
 #if defined(OS_MACOSX)
diff --git a/content/browser/renderer_host/render_widget_host_view_mus.h b/content/browser/renderer_host/render_widget_host_view_mus.h
index d3ae71dc..4029668 100644
--- a/content/browser/renderer_host/render_widget_host_view_mus.h
+++ b/content/browser/renderer_host/render_widget_host_view_mus.h
@@ -124,7 +124,6 @@
 
   RenderWidgetHostImpl* host_;
   scoped_ptr<mus::ScopedWindowPtr> window_;
-  gfx::Size size_;
   // The platform view for this RenderWidgetHostView.
   // RenderWidgetHostViewMus mostly only cares about stuff related to
   // compositing, the rest are directly forwared to this |platform_view_|.
diff --git a/content/browser/resource_loading_browsertest.cc b/content/browser/resource_loading_browsertest.cc
index 5765fe3..c68d577 100644
--- a/content/browser/resource_loading_browsertest.cc
+++ b/content/browser/resource_loading_browsertest.cc
@@ -16,12 +16,12 @@
 };
 
 const char kResourceLoadingNonMobilePage[] =
-    "files/resource_loading/resource_loading_non_mobile.html";
+    "/resource_loading/resource_loading_non_mobile.html";
 
 IN_PROC_BROWSER_TEST_F(ResourceLoadingBrowserTest,
   ResourceLoadingAvoidDoubleDownloads) {
-  ASSERT_TRUE(test_server()->Start());
-  GURL url = test_server()->GetURL(kResourceLoadingNonMobilePage);
+  ASSERT_TRUE(embedded_test_server()->Start());
+  GURL url = embedded_test_server()->GetURL(kResourceLoadingNonMobilePage);
   NavigateToURL(shell(), url);
   int data = -1;
   EXPECT_TRUE(ExecuteScriptAndExtractInt(shell()->web_contents(),
@@ -30,4 +30,3 @@
 }
 
 } // namespace content
-
diff --git a/content/browser/service_worker/service_worker_version.cc b/content/browser/service_worker/service_worker_version.cc
index 47083d1..6c0d21a 100644
--- a/content/browser/service_worker/service_worker_version.cc
+++ b/content/browser/service_worker/service_worker_version.cc
@@ -421,7 +421,8 @@
 }  // namespace
 
 const int ServiceWorkerVersion::kTimeoutTimerDelaySeconds = 30;
-const int ServiceWorkerVersion::kStartWorkerTimeoutMinutes = 5;
+const int ServiceWorkerVersion::kStartInstalledWorkerTimeoutSeconds = 10;
+const int ServiceWorkerVersion::kStartNewWorkerTimeoutMinutes = 5;
 const int ServiceWorkerVersion::kRequestTimeoutMinutes = 5;
 const int ServiceWorkerVersion::kStopWorkerTimeoutSeconds = 5;
 
@@ -1145,6 +1146,11 @@
   DCHECK_EQ(RUNNING, running_status());
   RestartTick(&idle_time_);
 
+  // Reset the interval to normal. If may have been shortened so starting an
+  // existing worker can timeout quickly.
+  SetTimeoutTimerInterval(
+      base::TimeDelta::FromSeconds(kTimeoutTimerDelaySeconds));
+
   // Fire all start callbacks.
   scoped_refptr<ServiceWorkerVersion> protect(this);
   RunCallbacks(this, &start_callbacks_, SERVICE_WORKER_OK);
@@ -1158,15 +1164,8 @@
   // Shorten the interval so stalling in stopped can be fixed quickly. Once the
   // worker stops, the timer is disabled. The interval will be reset to normal
   // when the worker starts up again.
-  DCHECK(timeout_timer_.IsRunning());
-  base::TimeDelta delay =
-      base::TimeDelta::FromSeconds(kStopWorkerTimeoutSeconds);
-  if (timeout_timer_.GetCurrentDelay() != delay) {
-    timeout_timer_.Stop();
-    timeout_timer_.Start(FROM_HERE, delay, this,
-                         &ServiceWorkerVersion::OnTimeoutTimer);
-  }
-
+  SetTimeoutTimerInterval(
+      base::TimeDelta::FromSeconds(kStopWorkerTimeoutSeconds));
   FOR_EACH_OBSERVER(Listener, listeners_, OnRunningStateChanged(this));
 }
 
@@ -2030,9 +2029,16 @@
   // Ping will be activated in OnScriptLoaded.
   ping_controller_->Deactivate();
 
+  // Make the timer delay shorter for starting an existing
+  // worker so stalled in starting workers can be timed out quickly.
+  // The timer will be reset to normal in OnStarted or the next start
+  // attempt.
+  const int delay_in_seconds = IsInstalled(status_)
+                                   ? kStartInstalledWorkerTimeoutSeconds
+                                   : kTimeoutTimerDelaySeconds;
   timeout_timer_.Start(FROM_HERE,
-                       base::TimeDelta::FromSeconds(kTimeoutTimerDelaySeconds),
-                       this, &ServiceWorkerVersion::OnTimeoutTimer);
+                       base::TimeDelta::FromSeconds(delay_in_seconds), this,
+                       &ServiceWorkerVersion::OnTimeoutTimer);
 }
 
 void ServiceWorkerVersion::StopTimeoutTimer() {
@@ -2047,6 +2053,15 @@
   }
 }
 
+void ServiceWorkerVersion::SetTimeoutTimerInterval(base::TimeDelta interval) {
+  DCHECK(timeout_timer_.IsRunning());
+  if (timeout_timer_.GetCurrentDelay() != interval) {
+    timeout_timer_.Stop();
+    timeout_timer_.Start(FROM_HERE, interval, this,
+                         &ServiceWorkerVersion::OnTimeoutTimer);
+  }
+}
+
 void ServiceWorkerVersion::OnTimeoutTimer() {
   DCHECK(running_status() == STARTING || running_status() == RUNNING ||
          running_status() == STOPPING)
@@ -2087,8 +2102,11 @@
   }
 
   // Starting a worker hasn't finished within a certain period.
-  if (GetTickDuration(start_time_) >
-      base::TimeDelta::FromMinutes(kStartWorkerTimeoutMinutes)) {
+  const base::TimeDelta start_limit =
+      IsInstalled(status())
+          ? base::TimeDelta::FromSeconds(kStartInstalledWorkerTimeoutSeconds)
+          : base::TimeDelta::FromMinutes(kStartNewWorkerTimeoutMinutes);
+  if (GetTickDuration(start_time_) > start_limit) {
     DCHECK(running_status() == STARTING || running_status() == STOPPING)
         << running_status();
     scoped_refptr<ServiceWorkerVersion> protect(this);
diff --git a/content/browser/service_worker/service_worker_version.h b/content/browser/service_worker/service_worker_version.h
index 3d474b72..2da6a3a 100644
--- a/content/browser/service_worker/service_worker_version.h
+++ b/content/browser/service_worker/service_worker_version.h
@@ -405,8 +405,10 @@
 
   // The timeout timer interval.
   static const int kTimeoutTimerDelaySeconds;
-  // Timeout for the worker to start.
-  static const int kStartWorkerTimeoutMinutes;
+  // Timeout for an installed worker to start.
+  static const int kStartInstalledWorkerTimeoutSeconds;
+  // Timeout for a new worker to start.
+  static const int kStartNewWorkerTimeoutMinutes;
   // Timeout for a request to be handled.
   static const int kRequestTimeoutMinutes;
   // Timeout for the worker to stop.
@@ -526,6 +528,7 @@
   void StartTimeoutTimer();
   void StopTimeoutTimer();
   void OnTimeoutTimer();
+  void SetTimeoutTimerInterval(base::TimeDelta interval);
 
   // Called by PingController for ping protocol.
   ServiceWorkerStatusCode PingWorker();
diff --git a/content/browser/service_worker/service_worker_version_unittest.cc b/content/browser/service_worker/service_worker_version_unittest.cc
index 55a6d91..e527f56 100644
--- a/content/browser/service_worker/service_worker_version_unittest.cc
+++ b/content/browser/service_worker/service_worker_version_unittest.cc
@@ -713,7 +713,7 @@
   version_->stale_time_ =
       base::TimeTicks::Now() -
       base::TimeDelta::FromMinutes(
-          ServiceWorkerVersion::kStartWorkerTimeoutMinutes + 1);
+          ServiceWorkerVersion::kStartNewWorkerTimeoutMinutes + 1);
   version_->OnTimeoutTimer();
   EXPECT_TRUE(version_->stale_time_.is_null());
   EXPECT_TRUE(version_->update_timer_.IsRunning());
@@ -728,7 +728,7 @@
   base::TimeTicks stale_time =
       base::TimeTicks::Now() -
       base::TimeDelta::FromMinutes(
-          ServiceWorkerVersion::kStartWorkerTimeoutMinutes + 1);
+          ServiceWorkerVersion::kStartNewWorkerTimeoutMinutes + 1);
   version_->stale_time_ = stale_time;
 
   // Stale time is not deferred.
@@ -822,7 +822,7 @@
   version_->start_time_ =
       base::TimeTicks::Now() -
       base::TimeDelta::FromMinutes(
-          ServiceWorkerVersion::kStartWorkerTimeoutMinutes + 1);
+          ServiceWorkerVersion::kStartNewWorkerTimeoutMinutes + 1);
   version_->timeout_timer_.user_task().Run();
   base::RunLoop().RunUntilIdle();
   EXPECT_EQ(SERVICE_WORKER_ERROR_TIMEOUT, status);
diff --git a/content/browser/site_per_process_browsertest.cc b/content/browser/site_per_process_browsertest.cc
index 007c6cd..cd46ef8f 100644
--- a/content/browser/site_per_process_browsertest.cc
+++ b/content/browser/site_per_process_browsertest.cc
@@ -4069,6 +4069,91 @@
   EXPECT_EQ("FOO", result);
 }
 
+// Ensure that sequential focus navigation (advancing focused elements with
+// <tab> and <shift-tab>) works across cross-process subframes.
+// The test sets up six inputs fields in a page with two cross-process
+// subframes:
+//                 child1            child2
+//             /------------\    /------------\.
+//             | 2. <input> |    | 4. <input> |
+//  1. <input> | 3. <input> |    | 5. <input> |  6. <input>
+//             \------------/    \------------/.
+//
+// The test then presses <tab> six times to cycle through focused elements 1-6.
+// The test then repeats this with <shift-tab> to cycle in reverse order.
+IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, SequentialFocusNavigation) {
+  GURL main_url(embedded_test_server()->GetURL(
+      "a.com", "/cross_site_iframe_factory.html?a(b,c)"));
+  EXPECT_TRUE(NavigateToURL(shell(), main_url));
+
+  WebContents* contents = shell()->web_contents();
+  FrameTreeNode* root =
+      static_cast<WebContentsImpl*>(contents)->GetFrameTree()->root();
+
+  // Assign a name to each frame.  This will be sent along in test messages
+  // from focus events.
+  EXPECT_TRUE(ExecuteScript(root->current_frame_host(),
+                            "window.name = 'root';"));
+  EXPECT_TRUE(ExecuteScript(root->child_at(0)->current_frame_host(),
+                            "window.name = 'child1';"));
+  EXPECT_TRUE(ExecuteScript(root->child_at(1)->current_frame_host(),
+                            "window.name = 'child2';"));
+
+  // This script will insert two <input> fields in the document, one at the
+  // beginning and one at the end.  For root frame, this means that we will
+  // have an <input>, then two <iframe> elements, then another <input>.
+  std::string script =
+      "function onFocus(e) {"
+      "  domAutomationController.setAutomationId(0);"
+      "  domAutomationController.send(window.name + '-focused-' + e.target.id);"
+      "}"
+      "var input1 = document.createElement('input');"
+      "input1.id = 'input1';"
+      "var input2 = document.createElement('input');"
+      "input2.id = 'input2';"
+      "document.body.insertBefore(input1, document.body.firstChild);"
+      "document.body.appendChild(input2);"
+      "input1.addEventListener('focus', onFocus, false);"
+      "input2.addEventListener('focus', onFocus, false);";
+
+  // Add two input fields to each of the three frames.
+  EXPECT_TRUE(ExecuteScript(root->current_frame_host(), script));
+  EXPECT_TRUE(ExecuteScript(root->child_at(0)->current_frame_host(), script));
+  EXPECT_TRUE(ExecuteScript(root->child_at(1)->current_frame_host(), script));
+
+  // Helper to simulate a tab press and wait for a focus message.
+  auto press_tab_and_wait_for_message = [contents](bool reverse) {
+    DOMMessageQueue msg_queue;
+    std::string reply;
+    SimulateKeyPress(contents, ui::VKEY_TAB, false, reverse /* shift */, false,
+                     false);
+    EXPECT_TRUE(msg_queue.WaitForMessage(&reply));
+    return reply;
+  };
+
+  // Press <tab> six times to focus each of the <input> elements in turn.
+  EXPECT_EQ("\"root-focused-input1\"", press_tab_and_wait_for_message(false));
+  EXPECT_EQ(root, root->frame_tree()->GetFocusedFrame());
+  EXPECT_EQ("\"child1-focused-input1\"", press_tab_and_wait_for_message(false));
+  EXPECT_EQ(root->child_at(0), root->frame_tree()->GetFocusedFrame());
+  EXPECT_EQ("\"child1-focused-input2\"", press_tab_and_wait_for_message(false));
+  EXPECT_EQ("\"child2-focused-input1\"", press_tab_and_wait_for_message(false));
+  EXPECT_EQ(root->child_at(1), root->frame_tree()->GetFocusedFrame());
+  EXPECT_EQ("\"child2-focused-input2\"", press_tab_and_wait_for_message(false));
+  EXPECT_EQ("\"root-focused-input2\"", press_tab_and_wait_for_message(false));
+  EXPECT_EQ(root, root->frame_tree()->GetFocusedFrame());
+
+  // Now, press <shift-tab> to navigate focus in the reverse direction.
+  EXPECT_EQ("\"child2-focused-input2\"", press_tab_and_wait_for_message(true));
+  EXPECT_EQ(root->child_at(1), root->frame_tree()->GetFocusedFrame());
+  EXPECT_EQ("\"child2-focused-input1\"", press_tab_and_wait_for_message(true));
+  EXPECT_EQ("\"child1-focused-input2\"", press_tab_and_wait_for_message(true));
+  EXPECT_EQ(root->child_at(0), root->frame_tree()->GetFocusedFrame());
+  EXPECT_EQ("\"child1-focused-input1\"", press_tab_and_wait_for_message(true));
+  EXPECT_EQ("\"root-focused-input1\"", press_tab_and_wait_for_message(true));
+  EXPECT_EQ(root, root->frame_tree()->GetFocusedFrame());
+}
+
 // A WebContentsDelegate to capture ContextMenu creation events.
 class ContextMenuObserverDelegate : public WebContentsDelegate {
  public:
diff --git a/content/browser/web_contents/web_contents_android.cc b/content/browser/web_contents/web_contents_android.cc
index e4fa397..9e301ab0 100644
--- a/content/browser/web_contents/web_contents_android.cc
+++ b/content/browser/web_contents/web_contents_android.cc
@@ -675,6 +675,11 @@
                                result_callback);
 }
 
+void WebContentsAndroid::OnContextMenuClosed(JNIEnv* env, jobject obj) {
+  static_cast<WebContentsImpl*>(web_contents_)
+      ->NotifyContextMenuClosed(CustomContextMenuContext());
+}
+
 void WebContentsAndroid::OnFinishGetContentBitmap(
     ScopedJavaGlobalRef<jobject>* obj,
     ScopedJavaGlobalRef<jobject>* callback,
@@ -690,4 +695,5 @@
                                                   java_bitmap.obj(),
                                                   response);
 }
+
 }  // namespace content
diff --git a/content/browser/web_contents/web_contents_android.h b/content/browser/web_contents/web_contents_android.h
index 1bc37393..c4eb33cf 100644
--- a/content/browser/web_contents/web_contents_android.h
+++ b/content/browser/web_contents/web_contents_android.h
@@ -174,6 +174,9 @@
                         jfloat y,
                         jfloat width,
                         jfloat height);
+
+  void OnContextMenuClosed(JNIEnv* env, jobject obj);
+
   void set_synchronous_compositor_client(SynchronousCompositorClient* client) {
     synchronous_compositor_client_ = client;
   }
diff --git a/content/child/BUILD.gn b/content/child/BUILD.gn
index 3ebac31..5a70f60a 100644
--- a/content/child/BUILD.gn
+++ b/content/child/BUILD.gn
@@ -72,15 +72,6 @@
       "npapi/plugin_instance.h",
       "npapi/plugin_lib.cc",
       "npapi/plugin_lib.h",
-      "npapi/plugin_stream.cc",
-      "npapi/plugin_stream.h",
-      "npapi/plugin_stream_posix.cc",
-      "npapi/plugin_stream_url.cc",
-      "npapi/plugin_stream_url.h",
-      "npapi/plugin_string_stream.cc",
-      "npapi/plugin_string_stream.h",
-      "npapi/plugin_url_fetcher.cc",
-      "npapi/plugin_url_fetcher.h",
       "npapi/webplugin.h",
       "npapi/webplugin_delegate.h",
       "npapi/webplugin_delegate_impl.cc",
@@ -98,7 +89,6 @@
       ]
     } else if (is_win) {
       sources -= [
-        "npapi/plugin_stream_win.cc",
         "npapi/webplugin_delegate_impl_win.cc",
         "npapi/webplugin_ime_win.cc",
         "npapi/webplugin_ime_win.h",
diff --git a/content/child/child_gpu_memory_buffer_manager.cc b/content/child/child_gpu_memory_buffer_manager.cc
index c83ceea6..21a512f 100644
--- a/content/child/child_gpu_memory_buffer_manager.cc
+++ b/content/child/child_gpu_memory_buffer_manager.cc
@@ -45,18 +45,13 @@
       content::GetNextGenericSharedMemoryId(), size.width(), size.height(),
       format, usage, &handle);
   bool success = sender_->Send(message);
-  if (!success || handle.is_null())
-    return nullptr;
+  CHECK(success);
+  CHECK(!handle.is_null());
 
   scoped_ptr<GpuMemoryBufferImpl> buffer(GpuMemoryBufferImpl::CreateFromHandle(
       handle, size, format, usage,
       base::Bind(&DeletedGpuMemoryBuffer, sender_, handle.id)));
-  if (!buffer) {
-    sender_->Send(new ChildProcessHostMsg_DeletedGpuMemoryBuffer(
-        handle.id, gpu::SyncToken()));
-    return nullptr;
-  }
-
+  CHECK(buffer);
   return buffer.Pass();
 }
 
diff --git a/content/child/npapi/plugin_host.cc b/content/child/npapi/plugin_host.cc
index ea7d0a0..4f3006e0 100644
--- a/content/child/npapi/plugin_host.cc
+++ b/content/child/npapi/plugin_host.cc
@@ -16,7 +16,6 @@
 #include "build/build_config.h"
 #include "content/child/npapi/plugin_instance.h"
 #include "content/child/npapi/plugin_lib.h"
-#include "content/child/npapi/plugin_stream_url.h"
 #include "content/child/npapi/webplugin_delegate.h"
 #include "content/public/common/content_client.h"
 #include "content/public/common/content_switches.h"
@@ -339,174 +338,28 @@
 
 // Requests a range of bytes for a seekable stream.
 NPError NPN_RequestRead(NPStream* stream, NPByteRange* range_list) {
-  if (!stream || !range_list)
-    return NPERR_GENERIC_ERROR;
-
-  scoped_refptr<PluginInstance> plugin(
-      reinterpret_cast<PluginInstance*>(stream->ndata));
-  if (!plugin.get())
-    return NPERR_GENERIC_ERROR;
-
-  plugin->RequestRead(stream, range_list);
-  return NPERR_NO_ERROR;
+  return NPERR_GENERIC_ERROR;
 }
 
-// Generic form of GetURL for common code between GetURL and GetURLNotify.
-static NPError GetURLNotify(NPP id,
-                            const char* url,
-                            const char* target,
-                            bool notify,
-                            void* notify_data) {
-  if (!url)
-    return NPERR_INVALID_URL;
-
-  scoped_refptr<PluginInstance> plugin(FindInstance(id));
-  if (!plugin.get()) {
-    return NPERR_GENERIC_ERROR;
-  }
-
-  plugin->RequestURL(url, "GET", target, NULL, 0, notify, notify_data);
-  return NPERR_NO_ERROR;
-}
-
-// Requests creation of a new stream with the contents of the
-// specified URL; gets notification of the result.
 NPError NPN_GetURLNotify(NPP id,
                          const char* url,
                          const char* target,
                          void* notify_data) {
-  // This is identical to NPN_GetURL, but after finishing, the
-  // browser will call NPP_URLNotify to inform the plugin that
-  // it has completed.
-
-  // According to the NPAPI documentation, if target == _self
-  // or a parent to _self, the browser should return NPERR_INVALID_PARAM,
-  // because it can't notify the plugin once deleted.  This is
-  // absolutely false; firefox doesn't do this, and Flash relies on
-  // being able to use this.
-
-  // Also according to the NPAPI documentation, we should return
-  // NPERR_INVALID_URL if the url requested is not valid.  However,
-  // this would require that we synchronously start fetching the
-  // URL.  That just isn't practical.  As such, there really is
-  // no way to return this error.  From looking at the Firefox
-  // implementation, it doesn't look like Firefox does this either.
-
-  return GetURLNotify(id, url, target, true, notify_data);
+  return NPERR_GENERIC_ERROR;
 }
 
 NPError NPN_GetURL(NPP id, const char* url, const char* target) {
-  // Notes:
-  //    Request from the Plugin to fetch content either for the plugin
-  //    or to be placed into a browser window.
-  //
-  // If target == null, the browser fetches content and streams to plugin.
-  //    otherwise, the browser loads content into an existing browser frame.
-  // If the target is the window/frame containing the plugin, the plugin
-  //    may be destroyed.
-  // If the target is _blank, a mailto: or news: url open content in a new
-  //    browser window
-  // If the target is _self, no other instance of the plugin is created.  The
-  //    plugin continues to operate in its own window
-
-  return GetURLNotify(id, url, target, false, 0);
-}
-
-// Generic form of PostURL for common code between PostURL and PostURLNotify.
-static NPError PostURLNotify(NPP id,
-                             const char* url,
-                             const char* target,
-                             uint32_t len,
-                             const char* buf,
-                             NPBool file,
-                             bool notify,
-                             void* notify_data) {
-  if (!url)
-    return NPERR_INVALID_URL;
-
-  scoped_refptr<PluginInstance> plugin(FindInstance(id));
-  if (!plugin.get()) {
-    NOTREACHED();
-    return NPERR_GENERIC_ERROR;
-  }
-
-  std::string post_file_contents;
-
-  if (file) {
-    // Post data to be uploaded from a file. This can be handled in two
-    // ways.
-    // 1. Read entire file and send the contents as if it was a post data
-    //    specified in the argument
-    // 2. Send just the file details and read them in the browser at the
-    //    time of sending the request.
-    // Approach 2 is more efficient but complicated. Approach 1 has a major
-    // drawback of sending potentially large data over two IPC hops.  In a way
-    // 'large data over IPC' problem exists as it is in case of plugin giving
-    // the data directly instead of in a file.
-    // Currently we are going with the approach 1 to get the feature working.
-    // We can optimize this later with approach 2.
-
-    // TODO(joshia): Design a scheme to send a file descriptor instead of
-    // entire file contents across.
-
-    // Security alert:
-    // ---------------
-    // Here we are blindly uploading whatever file requested by a plugin.
-    // This is risky as someone could exploit a plugin to send private
-    // data in arbitrary locations.
-    // A malicious (non-sandboxed) plugin has unfeterred access to OS
-    // resources and can do this anyway without using browser's HTTP stack.
-    // FWIW, Firefox and Safari don't perform any security checks.
-
-    if (!buf)
-      return NPERR_FILE_NOT_FOUND;
-
-    std::string file_path_ascii(buf);
-    base::FilePath file_path;
-    static const char kFileUrlPrefix[] = "file:";
-    if (base::StartsWith(file_path_ascii, kFileUrlPrefix,
-                         base::CompareCase::INSENSITIVE_ASCII)) {
-      GURL file_url(file_path_ascii);
-      DCHECK(file_url.SchemeIsFile());
-      net::FileURLToFilePath(file_url, &file_path);
-    } else {
-      file_path = base::FilePath::FromUTF8Unsafe(file_path_ascii);
-    }
-
-    base::File::Info post_file_info;
-    if (!base::GetFileInfo(file_path, &post_file_info) ||
-        post_file_info.is_directory)
-      return NPERR_FILE_NOT_FOUND;
-
-    if (!base::ReadFileToString(file_path, &post_file_contents))
-      return NPERR_FILE_NOT_FOUND;
-
-    buf = post_file_contents.c_str();
-    len = post_file_contents.size();
-  }
-
-  // The post data sent by a plugin contains both headers
-  // and post data.  Example:
-  //      Content-type: text/html
-  //      Content-length: 200
-  //
-  //      <200 bytes of content here>
-  //
-  // Unfortunately, our stream needs these broken apart,
-  // so we need to parse the data and set headers and data
-  // separately.
-  plugin->RequestURL(url, "POST", target, buf, len, notify, notify_data);
-  return NPERR_NO_ERROR;
+  return NPERR_GENERIC_ERROR;
 }
 
 NPError NPN_PostURLNotify(NPP id,
-                          const char* url,
-                          const char* target,
-                          uint32_t len,
-                          const char* buf,
-                          NPBool file,
-                          void* notify_data) {
-  return PostURLNotify(id, url, target, len, buf, file, true, notify_data);
+                    const char* url,
+                    const char* target,
+                    uint32_t len,
+                    const char* buf,
+                    NPBool file,
+                    void* notify_data) {
+  return NPERR_GENERIC_ERROR;
 }
 
 NPError NPN_PostURL(NPP id,
@@ -515,28 +368,7 @@
                     uint32_t len,
                     const char* buf,
                     NPBool file) {
-  // POSTs data to an URL, either from a temp file or a buffer.
-  // If file is true, buf contains a temp file (which host will delete after
-  //   completing), and len contains the length of the filename.
-  // If file is false, buf contains the data to send, and len contains the
-  //   length of the buffer
-  //
-  // If target is null,
-  //   server response is returned to the plugin
-  // If target is _current, _self, or _top,
-  //   server response is written to the plugin window and plugin is unloaded.
-  // If target is _new or _blank,
-  //   server response is written to a new browser window
-  // If target is an existing frame,
-  //   server response goes to that frame.
-  //
-  // For protocols other than FTP
-  //   file uploads must be line-end converted from \r\n to \n
-  //
-  // Note:  you cannot specify headers (even a blank line) in a memory buffer,
-  //        use NPN_PostURLNotify
-
-  return PostURLNotify(id, url, target, len, buf, file, false, 0);
+  return NPERR_GENERIC_ERROR;
 }
 
 NPError NPN_NewStream(NPP id,
@@ -1098,10 +930,6 @@
 }
 
 void NPN_URLRedirectResponse(NPP instance, void* notify_data, NPBool allow) {
-  scoped_refptr<PluginInstance> plugin(FindInstance(instance));
-  if (plugin.get()) {
-    plugin->URLRedirectResponse(!!allow, notify_data);
-  }
 }
 
 }  // extern "C"
diff --git a/content/child/npapi/plugin_instance.cc b/content/child/npapi/plugin_instance.cc
index c6c15441..4684fd7 100644
--- a/content/child/npapi/plugin_instance.cc
+++ b/content/child/npapi/plugin_instance.cc
@@ -15,8 +15,6 @@
 #include "build/build_config.h"
 #include "content/child/npapi/plugin_host.h"
 #include "content/child/npapi/plugin_lib.h"
-#include "content/child/npapi/plugin_stream_url.h"
-#include "content/child/npapi/plugin_string_stream.h"
 #include "content/child/npapi/webplugin.h"
 #include "content/child/npapi/webplugin_delegate.h"
 #include "content/child/npapi/webplugin_resource_client.h"
@@ -40,7 +38,6 @@
       transparent_(true),
       webplugin_(0),
       mime_type_(mime_type),
-      get_notify_data_(0),
       use_mozilla_user_agent_(false),
 #if defined (OS_MACOSX)
 #ifdef NP_NO_QUICKDRAW
@@ -57,11 +54,7 @@
 #endif
       task_runner_(base::ThreadTaskRunnerHandle::Get()),
       load_manually_(false),
-      in_close_streams_(false),
-      next_timer_id_(1),
-      next_notify_id_(0),
-      next_range_request_id_(0),
-      handles_url_redirects_(false) {
+      next_timer_id_(1) {
   npp_ = new NPP_t();
   npp_->ndata = 0;
   npp_->pdata = 0;
@@ -73,8 +66,6 @@
 }
 
 PluginInstance::~PluginInstance() {
-  CloseStreams();
-
   if (npp_ != 0) {
     delete npp_;
     npp_ = 0;
@@ -84,73 +75,6 @@
     plugin_->CloseInstance();
 }
 
-PluginStreamUrl* PluginInstance::CreateStream(unsigned long resource_id,
-                                              const GURL& url,
-                                              const std::string& mime_type,
-                                              int notify_id) {
-
-  bool notify;
-  void* notify_data;
-  GetNotifyData(notify_id, &notify, &notify_data);
-  PluginStreamUrl* stream = new PluginStreamUrl(
-      resource_id, url, this, notify, notify_data);
-
-  AddStream(stream);
-  return stream;
-}
-
-void PluginInstance::AddStream(PluginStream* stream) {
-  open_streams_.push_back(make_scoped_refptr(stream));
-}
-
-void PluginInstance::RemoveStream(PluginStream* stream) {
-  if (in_close_streams_)
-    return;
-
-  std::vector<scoped_refptr<PluginStream> >::iterator stream_index;
-  for (stream_index = open_streams_.begin();
-       stream_index != open_streams_.end(); ++stream_index) {
-    if (stream_index->get() == stream) {
-      open_streams_.erase(stream_index);
-      break;
-    }
-  }
-}
-
-bool PluginInstance::IsValidStream(const NPStream* stream) {
-  std::vector<scoped_refptr<PluginStream> >::iterator stream_index;
-  for (stream_index = open_streams_.begin();
-          stream_index != open_streams_.end(); ++stream_index) {
-    if ((*stream_index)->stream() == stream)
-      return true;
-  }
-
-  return false;
-}
-
-void PluginInstance::CloseStreams() {
-  in_close_streams_ = true;
-  for (unsigned int index = 0; index < open_streams_.size(); ++index) {
-    // Close all streams on the way down.
-    open_streams_[index]->Close(NPRES_USER_BREAK);
-  }
-  open_streams_.clear();
-  in_close_streams_ = false;
-}
-
-WebPluginResourceClient* PluginInstance::GetRangeRequest(
-    int id) {
-  PendingRangeRequestMap::iterator iter = pending_range_requests_.find(id);
-  if (iter == pending_range_requests_.end()) {
-    NOTREACHED();
-    return NULL;
-  }
-
-  WebPluginResourceClient* rv = iter->second->AsResourceClient();
-  pending_range_requests_.erase(iter);
-  return rv;
-}
-
 bool PluginInstance::Start(const GURL& url,
                            char** const param_names,
                            char** const param_values,
@@ -162,12 +86,6 @@
 
   NPError err = NPP_New(mode, param_count,
       const_cast<char **>(param_names), const_cast<char **>(param_values));
-
-  if (err == NPERR_NO_ERROR) {
-    handles_url_redirects_ =
-        ((npp_functions_->version >= NPVERS_HAS_URL_REDIRECT_HANDLING) &&
-         (npp_functions_->urlredirectnotify));
-  }
   return err == NPERR_NO_ERROR;
 }
 
@@ -192,21 +110,6 @@
   return true;
 }
 
-// WebPluginLoadDelegate methods
-void PluginInstance::DidFinishLoadWithReason(const GURL& url,
-                                             NPReason reason,
-                                             int notify_id) {
-  bool notify;
-  void* notify_data;
-  GetNotifyData(notify_id, &notify, &notify_data);
-  if (!notify) {
-    NOTREACHED();
-    return;
-  }
-
-  NPP_URLNotify(url.spec().c_str(), reason, notify_data);
-}
-
 unsigned PluginInstance::GetBackingTextureId() {
   // By default the plugin instance is not backed by an OpenGL texture.
   return 0;
@@ -280,7 +183,7 @@
   DCHECK(npp_functions_ != 0);
   DCHECK(npp_functions_->destroystream != 0);
 
-  if (stream == NULL || !IsValidStream(stream) || (stream->ndata == NULL))
+  if (stream == NULL || (stream->ndata == NULL))
     return NPERR_INVALID_INSTANCE_ERROR;
 
   if (npp_functions_->destroystream != 0) {
@@ -326,16 +229,6 @@
   files_created_.push_back(file_name);
 }
 
-void PluginInstance::NPP_URLNotify(const char* url,
-                                   NPReason reason,
-                                   void* notifyData) {
-  DCHECK(npp_functions_ != 0);
-  DCHECK(npp_functions_->urlnotify != 0);
-  if (npp_functions_->urlnotify != 0) {
-    npp_functions_->urlnotify(npp_, url, reason, notifyData);
-  }
-}
-
 NPError PluginInstance::NPP_GetValue(NPPVariable variable, void* value) {
   DCHECK(npp_functions_ != 0);
   // getvalue is NULL for Shockwave
@@ -371,71 +264,6 @@
   return false;
 }
 
-void PluginInstance::NPP_URLRedirectNotify(const char* url, int32_t status,
-                                           void* notify_data) {
-  DCHECK(npp_functions_ != 0);
-  if (npp_functions_->urlredirectnotify != 0) {
-    npp_functions_->urlredirectnotify(npp_, url, status, notify_data);
-  }
-}
-
-void PluginInstance::SendJavaScriptStream(const GURL& url,
-                                          const std::string& result,
-                                          bool success,
-                                          int notify_id) {
-  bool notify;
-  void* notify_data;
-  GetNotifyData(notify_id, &notify, &notify_data);
-
-  if (success) {
-    PluginStringStream *stream =
-        new PluginStringStream(this, url, notify, notify_data);
-    AddStream(stream);
-    stream->SendToPlugin(result, "text/html");
-  } else {
-    // NOTE: Sending an empty stream here will crash MacroMedia
-    // Flash 9.  Just send the URL Notify.
-    if (notify)
-      NPP_URLNotify(url.spec().c_str(), NPRES_DONE, notify_data);
-  }
-}
-
-void PluginInstance::DidReceiveManualResponse(const GURL& url,
-                                              const std::string& mime_type,
-                                              const std::string& headers,
-                                              uint32 expected_length,
-                                              uint32 last_modified) {
-  DCHECK(load_manually_);
-
-  plugin_data_stream_ =
-      CreateStream(static_cast<unsigned long>(-1), url, mime_type, 0);
-  plugin_data_stream_->DidReceiveResponse(mime_type, headers, expected_length,
-                                          last_modified, true);
-}
-
-void PluginInstance::DidReceiveManualData(const char* buffer, int length) {
-  DCHECK(load_manually_);
-  if (plugin_data_stream_.get() != NULL) {
-    plugin_data_stream_->DidReceiveData(buffer, length, 0);
-  }
-}
-
-void PluginInstance::DidFinishManualLoading() {
-  DCHECK(load_manually_);
-  if (plugin_data_stream_.get() != NULL) {
-    plugin_data_stream_->DidFinishLoading(plugin_data_stream_->ResourceId());
-    plugin_data_stream_->Close(NPRES_DONE);
-    plugin_data_stream_ = NULL;
-  }
-}
-
-void PluginInstance::DidManualLoadFail() {
-  DCHECK(load_manually_);
-  if (plugin_data_stream_.get() != NULL) {
-    plugin_data_stream_->DidFail(plugin_data_stream_->ResourceId());
-    plugin_data_stream_ = NULL;
-  }
-}
 
 void PluginInstance::PluginThreadAsyncCall(void (*func)(void*),
                                            void* user_data) {
@@ -526,76 +354,6 @@
   popups_enabled_stack_.pop();
 }
 
-void PluginInstance::RequestRead(NPStream* stream, NPByteRange* range_list) {
-  std::string range_info = "bytes=";
-
-  while (range_list) {
-    range_info += base::IntToString(range_list->offset);
-    range_info.push_back('-');
-    range_info +=
-        base::UintToString(range_list->offset + range_list->length - 1);
-    range_list = range_list->next;
-    if (range_list)
-      range_info.push_back(',');
-  }
-
-  if (plugin_data_stream_.get()) {
-    if (plugin_data_stream_->stream() == stream) {
-      webplugin_->CancelDocumentLoad();
-      plugin_data_stream_ = NULL;
-    }
-  }
-
-  // The lifetime of a NPStream instance depends on the PluginStream instance
-  // which owns it. When a plugin invokes NPN_RequestRead on a seekable stream,
-  // we don't want to create a new stream when the corresponding response is
-  // received. We send over a cookie which represents the PluginStream
-  // instance which is sent back from the renderer when the response is
-  // received.
-  std::vector<scoped_refptr<PluginStream> >::iterator stream_index;
-  for (stream_index = open_streams_.begin();
-          stream_index != open_streams_.end(); ++stream_index) {
-    PluginStream* plugin_stream = stream_index->get();
-    if (plugin_stream->stream() == stream) {
-      // A stream becomes seekable the first time NPN_RequestRead
-      // is called on it.
-      plugin_stream->set_seekable(true);
-
-      if (base::CommandLine::ForCurrentProcess()->HasSwitch(
-              switches::kDisableDirectNPAPIRequests)) {
-        pending_range_requests_[++next_range_request_id_] = plugin_stream;
-        webplugin_->InitiateHTTPRangeRequest(
-            stream->url, range_info.c_str(), next_range_request_id_);
-        return;
-      } else {
-        PluginStreamUrl* plugin_stream_url =
-            static_cast<PluginStreamUrl*>(plugin_stream);
-        plugin_stream_url->FetchRange(range_info);
-        return;
-      }
-    }
-  }
-  NOTREACHED();
-}
-
-void PluginInstance::RequestURL(const char* url,
-                                const char* method,
-                                const char* target,
-                                const char* buf,
-                                unsigned int len,
-                                bool notify,
-                                void* notify_data) {
-  int notify_id = 0;
-  if (notify) {
-    notify_id = ++next_notify_id_;
-    pending_requests_[notify_id] = notify_data;
-  }
-
-  webplugin_->HandleURLRequest(
-      url, method, target, buf, len, notify_id, popups_allowed(),
-      notify ? handles_url_redirects_ : false);
-}
-
 bool PluginInstance::ConvertPoint(double source_x, double source_y,
                                   NPCoordinateSpace source_space,
                                   double* dest_x, double* dest_y,
@@ -666,33 +424,4 @@
 #endif
 }
 
-void PluginInstance::GetNotifyData(int notify_id,
-                                   bool* notify,
-                                   void** notify_data) {
-  PendingRequestMap::iterator iter = pending_requests_.find(notify_id);
-  if (iter != pending_requests_.end()) {
-    *notify = true;
-    *notify_data = iter->second;
-    pending_requests_.erase(iter);
-  } else {
-    *notify = false;
-    *notify_data = NULL;
-  }
-}
-
-void PluginInstance::URLRedirectResponse(bool allow, void* notify_data) {
-  // The notify_data passed in allows us to identify the matching stream.
-  std::vector<scoped_refptr<PluginStream> >::iterator stream_index;
-  for (stream_index = open_streams_.begin();
-          stream_index != open_streams_.end(); ++stream_index) {
-    PluginStream* plugin_stream = stream_index->get();
-    if (plugin_stream->notify_data() == notify_data) {
-      PluginStreamUrl* plugin_stream_url =
-          static_cast<PluginStreamUrl*>(plugin_stream);
-      plugin_stream_url->URLRedirectResponse(allow);
-      break;
-    }
-  }
-}
-
 }  // namespace content
diff --git a/content/child/npapi/plugin_instance.h b/content/child/npapi/plugin_instance.h
index 9558930..bf5a5fe0 100644
--- a/content/child/npapi/plugin_instance.h
+++ b/content/child/npapi/plugin_instance.h
@@ -31,8 +31,6 @@
 
 class PluginLib;
 class PluginHost;
-class PluginStream;
-class PluginStreamUrl;
 class WebPlugin;
 class WebPluginResourceClient;
 
@@ -121,30 +119,6 @@
   }
 #endif
 
-  // Creates a stream for sending an URL.  If notify_id is non-zero, it will
-  // send a notification to the plugin when the stream is complete; otherwise it
-  // will not.  Set object_url to true if the load is for the object tag's url,
-  // or false if it's for a url that the plugin fetched through
-  // NPN_GetUrl[Notify].
-  PluginStreamUrl* CreateStream(unsigned long resource_id,
-                                const GURL& url,
-                                const std::string& mime_type,
-                                int notify_id);
-
-  // For each instance, we track all streams.  When the
-  // instance closes, all remaining streams are also
-  // closed.  All streams associated with this instance
-  // should call AddStream so that they can be cleaned
-  // up when the instance shuts down.
-  void AddStream(PluginStream* stream);
-
-  // This is called when a stream is closed. We remove the stream from the
-  // list, which releases the reference maintained to the stream.
-  void RemoveStream(PluginStream* stream);
-
-  // Closes all open streams on this instance.
-  void CloseStreams();
-
   // Returns the WebPluginResourceClient object for a stream that has become
   // seekable.
   WebPluginResourceClient* GetRangeRequest(int id);
@@ -155,10 +129,6 @@
   // Returns the form value of this instance.
   bool GetFormValue(base::string16* value);
 
-  // WebViewDelegate methods that we implement. This is for handling
-  // callbacks during getURLNotify.
-  void DidFinishLoadWithReason(const GURL& url, NPReason reason, int notify_id);
-
   // If true, send the Mozilla user agent instead of Chrome's to the plugin.
   bool use_mozilla_user_agent() { return use_mozilla_user_agent_; }
   void set_use_mozilla_user_agent() { use_mozilla_user_agent_ = true; }
@@ -205,17 +175,7 @@
 
   void SendJavaScriptStream(const GURL& url,
                             const std::string& result,
-                            bool success,
-                            int notify_id);
-
-  void DidReceiveManualResponse(const GURL& url,
-                                const std::string& mime_type,
-                                const std::string& headers,
-                                uint32 expected_length,
-                                uint32 last_modified);
-  void DidReceiveManualData(const char* buffer, int length);
-  void DidFinishManualLoading();
-  void DidManualLoadFail();
+                            bool success);
 
   void PushPopupsEnabledState(bool enabled);
   void PopPopupsEnabledState();
@@ -224,25 +184,6 @@
     return popups_enabled_stack_.empty() ? false : popups_enabled_stack_.top();
   }
 
-  // Initiates byte range reads for plugins.
-  void RequestRead(NPStream* stream, NPByteRange* range_list);
-
-  // Handles GetURL/GetURLNotify/PostURL/PostURLNotify requests initiated
-  // by plugins.
-  void RequestURL(const char* url,
-                  const char* method,
-                  const char* target,
-                  const char* buf,
-                  unsigned int len,
-                  bool notify,
-                  void* notify_data);
-
-  // Handles NPN_URLRedirectResponse calls issued by plugins in response to
-  // HTTP URL redirect notifications.
-  void URLRedirectResponse(bool allow, void* notify_data);
-
-  bool handles_url_redirects() const { return handles_url_redirects_; }
-
  private:
   friend class base::RefCountedThreadSafe<PluginInstance>;
 
@@ -261,8 +202,6 @@
   void OnPluginThreadAsyncCall(void (*func)(void *), void* userData);
   void OnTimerCall(void (*func)(NPP id, uint32 timer_id),
                    NPP id, uint32 timer_id);
-  bool IsValidStream(const NPStream* stream);
-  void GetNotifyData(int notify_id, bool* notify, void** notify_data);
 
   // This is a hack to get the real player plugin to work with chrome
   // The real player plugin dll(nppl3260) when loaded by firefox is loaded via
@@ -289,14 +228,11 @@
   NPP                                      npp_;
   scoped_refptr<PluginHost>                host_;
   NPPluginFuncs*                           npp_functions_;
-  std::vector<scoped_refptr<PluginStream> > open_streams_;
   gfx::PluginWindowHandle                  window_handle_;
   bool                                     windowless_;
   bool                                     transparent_;
   WebPlugin*                               webplugin_;
   std::string                              mime_type_;
-  GURL                                     get_url_;
-  intptr_t                                 get_notify_data_;
   bool                                     use_mozilla_user_agent_;
 #if defined(OS_MACOSX)
   NPDrawingModel                           drawing_model_;
@@ -306,7 +242,6 @@
   NPCocoaEvent*                            currently_handled_event_;  // weak
 #endif
   scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
-  scoped_refptr<PluginStreamUrl>           plugin_data_stream_;
 
   // This flag if true indicates that the plugin data would be passed from
   // webkit. if false indicates that the plugin should download the data.
@@ -316,9 +251,6 @@
   // NPN_GetURL/NPN_GetURLNotify calls.
   std::stack<bool>                         popups_enabled_stack_;
 
-  // True if in CloseStreams().
-  bool in_close_streams_;
-
   // List of files created for the current plugin instance. File names are
   // added to the list every time the NPP_StreamAsFile function is called.
   std::vector<base::FilePath> files_created_;
@@ -334,21 +266,6 @@
   typedef std::map<uint32, TimerInfo> TimerMap;
   TimerMap timers_;
 
-  // Tracks pending GET/POST requests so that the plugin-given data doesn't
-  // cross process boundaries to an untrusted process.
-  typedef std::map<int, void*> PendingRequestMap;
-  PendingRequestMap pending_requests_;
-  int next_notify_id_;
-
-  // Used to track pending range requests so that when WebPlugin replies to us
-  // we can match the reply to the stream.
-  typedef std::map<int, scoped_refptr<PluginStream> > PendingRangeRequestMap;
-  PendingRangeRequestMap pending_range_requests_;
-  int next_range_request_id_;
-  // The plugin handles the NPAPI URL redirect notification API.
-  // See here https://wiki.mozilla.org/NPAPI:HTTPRedirectHandling
-  bool handles_url_redirects_;
-
   DISALLOW_COPY_AND_ASSIGN(PluginInstance);
 };
 
diff --git a/content/child/npapi/plugin_stream.cc b/content/child/npapi/plugin_stream.cc
deleted file mode 100644
index 282f69b..0000000
--- a/content/child/npapi/plugin_stream.cc
+++ /dev/null
@@ -1,282 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// TODO : Support NP_ASFILEONLY mode
-// TODO : Support NP_SEEK mode
-// TODO : Support SEEKABLE=true in NewStream
-
-#include "content/child/npapi/plugin_stream.h"
-
-#include <algorithm>
-
-#include "base/bind.h"
-#include "base/location.h"
-#include "base/single_thread_task_runner.h"
-#include "base/strings/string_util.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/thread_task_runner_handle.h"
-#include "content/child/npapi/plugin_instance.h"
-#include "net/base/mime_util.h"
-#include "url/gurl.h"
-
-namespace content {
-
-PluginStream::PluginStream(
-    PluginInstance* instance,
-    const char* url,
-    bool need_notify,
-    void* notify_data)
-    : instance_(instance),
-      notify_needed_(need_notify),
-      notify_data_(notify_data),
-      close_on_write_data_(false),
-      requested_plugin_mode_(NP_NORMAL),
-      opened_(false),
-      data_offset_(0),
-      seekable_stream_(false) {
-  memset(&stream_, 0, sizeof(stream_));
-  stream_.url = base::strdup(url);
-  ResetTempFileHandle();
-  ResetTempFileName();
-}
-
-PluginStream::~PluginStream() {
-  // always close our temporary files.
-  CloseTempFile();
-  free(const_cast<char*>(stream_.url));
-}
-
-bool PluginStream::Open(const std::string& mime_type,
-                        const std::string& headers,
-                        uint32 length,
-                        uint32 last_modified,
-                        bool request_is_seekable) {
-  headers_ = headers;
-  NPP id = instance_->npp();
-  stream_.end = length;
-  stream_.lastmodified = last_modified;
-  stream_.pdata = 0;
-  stream_.ndata = id->ndata;
-  stream_.notifyData = notify_data_;
-  if (!headers_.empty())
-    stream_.headers = headers_.c_str();
-
-  bool seekable_stream = false;
-  if (request_is_seekable) {
-    std::string headers_lc = base::ToLowerASCII(headers);
-    if (headers_lc.find("accept-ranges: bytes") != std::string::npos) {
-      seekable_stream = true;
-    }
-  }
-
-  const char* char_mime_type = "application/x-unknown-content-type";
-  std::string temp_mime_type;
-  if (!mime_type.empty()) {
-    char_mime_type = mime_type.c_str();
-  } else {
-    GURL gurl(stream_.url);
-
-    base::FilePath path = base::FilePath::FromUTF8Unsafe(gurl.path());
-    if (net::GetMimeTypeFromFile(path, &temp_mime_type))
-      char_mime_type = temp_mime_type.c_str();
-  }
-
-  // Silverlight expects a valid mime type
-  DCHECK_NE(0U, strlen(char_mime_type));
-  NPError err = instance_->NPP_NewStream((NPMIMEType)char_mime_type,
-                                         &stream_, seekable_stream,
-                                         &requested_plugin_mode_);
-  if (err != NPERR_NO_ERROR) {
-    Notify(err);
-    return false;
-  }
-
-  opened_ = true;
-
-  if (requested_plugin_mode_ == NP_SEEK) {
-    seekable_stream_ = true;
-  }
-  // If the plugin has requested certain modes, then we need a copy
-  // of this file on disk.  Open it and save it as we go.
-  if (RequestedPluginModeIsAsFile()) {
-    if (OpenTempFile() == false) {
-      return false;
-    }
-  }
-
-  mime_type_ = char_mime_type;
-  return true;
-}
-
-int PluginStream::Write(const char* buffer, const int length,
-                        int data_offset) {
-  // There may be two streams to write to - the plugin and the file.
-  // It is unclear what to do if we cannot write to both.  The rules of
-  // this function are that the plugin must consume at least as many
-  // bytes as returned by the WriteReady call.  So, we will attempt to
-  // write that many to both streams.  If we can't write that many bytes
-  // to each stream, we'll return failure.
-
-  DCHECK(opened_);
-  if (WriteToFile(buffer, length) &&
-      WriteToPlugin(buffer, length, data_offset)) {
-    return length;
-  }
-
-  return -1;
-}
-
-bool PluginStream::WriteToFile(const char* buf, size_t length) {
-  // For ASFILEONLY, ASFILE, and SEEK modes, we need to write
-  // to the disk
-  if (TempFileIsValid() && RequestedPluginModeIsAsFile()) {
-    size_t totalBytesWritten = 0, bytes;
-    do {
-      bytes = WriteBytes(buf, length);
-      totalBytesWritten += bytes;
-    } while (bytes > 0U && totalBytesWritten < length);
-
-    if (totalBytesWritten != length) {
-      return false;
-    }
-  }
-
-  return true;
-}
-
-bool PluginStream::WriteToPlugin(const char* buf, const int length,
-                                 const int data_offset) {
-  // For NORMAL and ASFILE modes, we send the data to the plugin now
-  if (requested_plugin_mode_ != NP_NORMAL &&
-      requested_plugin_mode_ != NP_ASFILE &&
-      requested_plugin_mode_ != NP_SEEK) {
-    return true;
-  }
-
-  int written = TryWriteToPlugin(buf, length, data_offset);
-  if (written == -1)
-    return false;
-
-  if (written < length) {
-    // Buffer the remaining data.
-    size_t remaining = length - written;
-    size_t previous_size = delivery_data_.size();
-    delivery_data_.resize(previous_size + remaining);
-    data_offset_ = data_offset;
-    memcpy(&delivery_data_[previous_size], buf + written, remaining);
-    base::ThreadTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE, base::Bind(&PluginStream::OnDelayDelivery, this));
-  }
-
-  return true;
-}
-
-void PluginStream::OnDelayDelivery() {
-  // It is possible that the plugin stream may have closed before the task
-  // was hit.
-  if (!opened_)
-    return;
-
-  int size = static_cast<int>(delivery_data_.size());
-  int written = TryWriteToPlugin(&delivery_data_.front(), size, data_offset_);
-  if (written > 0) {
-    // Remove the data that we already wrote.
-    delivery_data_.erase(delivery_data_.begin(),
-                         delivery_data_.begin() + written);
-  }
-}
-
-int PluginStream::TryWriteToPlugin(const char* buf, const int length,
-                                   const int data_offset) {
-  int byte_offset = 0;
-
-  if (data_offset > 0)
-    data_offset_ = data_offset;
-
-  while (byte_offset < length) {
-    int bytes_remaining = length - byte_offset;
-    int bytes_to_write = instance_->NPP_WriteReady(&stream_);
-    if (bytes_to_write > bytes_remaining)
-      bytes_to_write = bytes_remaining;
-
-    if (bytes_to_write == 0)
-      return byte_offset;
-
-    int bytes_consumed = instance_->NPP_Write(
-        &stream_, data_offset_, bytes_to_write,
-        const_cast<char*>(buf + byte_offset));
-    if (bytes_consumed < 0) {
-      // The plugin failed, which means that we need to close the stream.
-      Close(NPRES_NETWORK_ERR);
-      return -1;
-    }
-    if (bytes_consumed == 0) {
-      // The plugin couldn't take all of the data now.
-      return byte_offset;
-    }
-
-    // The plugin might report more that we gave it.
-    bytes_consumed = std::min(bytes_consumed, bytes_to_write);
-
-    data_offset_ += bytes_consumed;
-    byte_offset += bytes_consumed;
-  }
-
-  if (close_on_write_data_)
-    Close(NPRES_DONE);
-
-  return length;
-}
-
-bool PluginStream::Close(NPReason reason) {
-  if (opened_ == true) {
-    opened_ = false;
-
-    if (delivery_data_.size()) {
-      if (reason == NPRES_DONE) {
-        // There is more data to be streamed, don't destroy the stream now.
-        close_on_write_data_ = true;
-        return true;
-      } else {
-        // Stop any pending data from being streamed
-        delivery_data_.resize(0);
-      }
-    }
-
-    // If we have a temp file, be sure to close it.
-    // Also, allow the plugin to access it now.
-    if (TempFileIsValid()) {
-      CloseTempFile();
-      if (reason == NPRES_DONE)
-        WriteAsFile();
-    }
-
-    if (stream_.ndata != NULL) {
-      // Stream hasn't been closed yet.
-      NPError err = instance_->NPP_DestroyStream(&stream_, reason);
-      DCHECK(err == NPERR_NO_ERROR);
-    }
-  }
-
-  Notify(reason);
-  return true;
-}
-
-WebPluginResourceClient* PluginStream::AsResourceClient() {
-  return NULL;
-}
-
-void PluginStream::Notify(NPReason reason) {
-  if (notify_needed_) {
-    instance_->NPP_URLNotify(stream_.url, reason, notify_data_);
-    notify_needed_ = false;
-  }
-}
-
-bool PluginStream::RequestedPluginModeIsAsFile() const {
-  return (requested_plugin_mode_ == NP_ASFILE ||
-          requested_plugin_mode_ == NP_ASFILEONLY);
-}
-
-}  // namespace content
diff --git a/content/child/npapi/plugin_stream.h b/content/child/npapi/plugin_stream.h
deleted file mode 100644
index 644e16c..0000000
--- a/content/child/npapi/plugin_stream.h
+++ /dev/null
@@ -1,148 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_CHILD_NPAPI_PLUGIN_STREAM_H_
-#define CONTENT_CHILD_NPAPI_PLUGIN_STREAM_H_
-
-#include <string>
-#include <vector>
-
-#include "base/files/file_path.h"
-#include "base/memory/ref_counted.h"
-#include "build/build_config.h"
-#include "third_party/npapi/bindings/npapi.h"
-
-namespace content {
-
-class PluginInstance;
-class WebPluginResourceClient;
-
-// Base class for a NPAPI stream.  Tracks basic elements
-// of a stream for NPAPI notifications and stream position.
-class PluginStream : public base::RefCounted<PluginStream> {
- public:
-  // Create a new PluginStream object.  If needNotify is true, then the
-  // plugin will be notified when the stream has been fully sent.
-  PluginStream(PluginInstance* instance,
-               const char* url,
-               bool need_notify,
-               void* notify_data);
-
-  // Opens the stream to the Plugin.
-  // If the mime-type is not specified, we'll try to find one based on the
-  // mime-types table and the extension (if any) in the URL.
-  // If the size of the stream is known, use length to set the size.  If
-  // not known, set length to 0.
-  // The request_is_seekable parameter indicates whether byte range requests
-  // can be issued on the stream.
-  bool Open(const std::string &mime_type,
-            const std::string &headers,
-            uint32 length,
-            uint32 last_modified,
-            bool request_is_seekable);
-
-  // Writes to the stream.
-  int Write(const char* buf, const int len, int data_offset);
-
-  // Write the result as a file.
-  void WriteAsFile();
-
-  // Notify the plugin that a stream is complete.
-  void Notify(NPReason reason);
-
-  // Close the stream.
-  virtual bool Close(NPReason reason);
-
-  virtual WebPluginResourceClient* AsResourceClient();
-
-  // Cancels any HTTP requests initiated by the stream.
-  virtual void CancelRequest() {}
-
-  NPStream* stream() { return &stream_; }
-
-  PluginInstance* instance() { return instance_.get(); }
-
-  // setter/getter for the seekable attribute on the stream.
-  bool seekable() const { return seekable_stream_; }
-
-  void set_seekable(bool seekable) { seekable_stream_ = seekable; }
-
-  // getters for reading the notification related attributes on the stream.
-  bool notify_needed() const { return notify_needed_; }
-
-  void* notify_data() const { return notify_data_; }
-
- protected:
-  friend class base::RefCounted<PluginStream>;
-
-  virtual ~PluginStream();
-
-  // Check if the stream is open.
-  bool open() { return opened_; }
-
- private:
-  // Per platform method to reset the temporary file handle.
-  void ResetTempFileHandle();
-
-  // Per platform method to reset the temporary file name.
-  void ResetTempFileName();
-
-  // Open a temporary file for this stream.
-  // If successful, will set temp_file_name_, temp_file_handle_, and
-  // return true.
-  bool OpenTempFile();
-
-  // Closes the temporary file if it is open.
-  void CloseTempFile();
-
-  // Sends the data to the file. Called From WriteToFile.
-  size_t WriteBytes(const char* buf, size_t length);
-
-  // Sends the data to the file if it's open.
-  bool WriteToFile(const char* buf, size_t length);
-
-  // Sends the data to the plugin.  If it's not ready, handles buffering it
-  // and retrying later.
-  bool WriteToPlugin(const char* buf, const int length, const int data_offset);
-
-  // Send the data to the plugin, returning how many bytes it accepted, or -1
-  // if an error occurred.
-  int TryWriteToPlugin(const char* buf, const int length,
-                       const int data_offset);
-
-  // The callback which calls TryWriteToPlugin.
-  void OnDelayDelivery();
-
-  // Returns true if the temp file is valid and open for writing.
-  bool TempFileIsValid() const;
-
-  // Returns true if |requested_plugin_mode_| is NP_ASFILE or NP_ASFILEONLY.
-  bool RequestedPluginModeIsAsFile() const;
-
- private:
-  NPStream                      stream_;
-  std::string                   headers_;
-  scoped_refptr<PluginInstance> instance_;
-  bool                          notify_needed_;
-  void*                         notify_data_;
-  bool                          close_on_write_data_;
-  uint16                        requested_plugin_mode_;
-  bool                          opened_;
-#if defined(OS_WIN)
-  char                          temp_file_name_[MAX_PATH];
-  HANDLE                        temp_file_handle_;
-#elif defined(OS_POSIX)
-  FILE*                         temp_file_;
-  base::FilePath                temp_file_path_;
-#endif
-  std::vector<char>             delivery_data_;
-  int                           data_offset_;
-  bool                          seekable_stream_;
-  std::string                   mime_type_;
-  DISALLOW_COPY_AND_ASSIGN(PluginStream);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_CHILD_NPAPI_PLUGIN_STREAM_H_
diff --git a/content/child/npapi/plugin_stream_posix.cc b/content/child/npapi/plugin_stream_posix.cc
deleted file mode 100644
index ed9687c..0000000
--- a/content/child/npapi/plugin_stream_posix.cc
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/child/npapi/plugin_stream.h"
-
-#include <string.h>
-
-#include "base/files/file_path.h"
-#include "base/files/file_util.h"
-#include "base/logging.h"
-#include "content/child/npapi/plugin_instance.h"
-
-namespace content {
-
-void PluginStream::ResetTempFileHandle() {
-  temp_file_ = NULL;
-}
-
-void PluginStream::ResetTempFileName() {
-  temp_file_path_ = base::FilePath();
-}
-
-void PluginStream::WriteAsFile() {
-  if (RequestedPluginModeIsAsFile())
-    instance_->NPP_StreamAsFile(&stream_, temp_file_path_.value().c_str());
-}
-
-size_t PluginStream::WriteBytes(const char* buf, size_t length) {
-  return fwrite(buf, sizeof(char), length, temp_file_);
-}
-
-bool PluginStream::OpenTempFile() {
-  DCHECK_EQ(static_cast<FILE*>(NULL), temp_file_);
-
-  if (base::CreateTemporaryFile(&temp_file_path_))
-    temp_file_ = base::OpenFile(temp_file_path_, "a");
-
-  if (!temp_file_) {
-    base::DeleteFile(temp_file_path_, false);
-    ResetTempFileName();
-    return false;
-  }
-  return true;
-}
-
-void PluginStream::CloseTempFile() {
-  if (!TempFileIsValid())
-    return;
-
-  base::CloseFile(temp_file_);
-  ResetTempFileHandle();
-}
-
-bool PluginStream::TempFileIsValid() const {
-  return temp_file_ != NULL;
-}
-
-}  // namespace content
diff --git a/content/child/npapi/plugin_stream_url.cc b/content/child/npapi/plugin_stream_url.cc
deleted file mode 100644
index 84490d7d..0000000
--- a/content/child/npapi/plugin_stream_url.cc
+++ /dev/null
@@ -1,217 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/child/npapi/plugin_stream_url.h"
-
-#include <algorithm>
-
-#include "base/stl_util.h"
-#include "base/strings/string_util.h"
-#include "content/child/npapi/plugin_host.h"
-#include "content/child/npapi/plugin_instance.h"
-#include "content/child/npapi/plugin_lib.h"
-#include "content/child/npapi/plugin_url_fetcher.h"
-#include "content/child/npapi/webplugin.h"
-#include "net/http/http_response_headers.h"
-
-namespace content {
-
-PluginStreamUrl::PluginStreamUrl(
-    unsigned long resource_id,
-    const GURL &url,
-    PluginInstance *instance,
-    bool notify_needed,
-    void *notify_data)
-    : PluginStream(instance, url.spec().c_str(), notify_needed, notify_data),
-      url_(url),
-      id_(resource_id) {
-}
-
-void PluginStreamUrl::SetPluginURLFetcher(PluginURLFetcher* fetcher) {
-  plugin_url_fetcher_.reset(fetcher);
-}
-
-void PluginStreamUrl::URLRedirectResponse(bool allow) {
-  if (plugin_url_fetcher_.get()) {
-    plugin_url_fetcher_->URLRedirectResponse(allow);
-  } else {
-    instance()->webplugin()->URLRedirectResponse(allow, id_);
-  }
-
-  if (allow)
-    UpdateUrl(pending_redirect_url_.c_str());
-}
-
-void PluginStreamUrl::FetchRange(const std::string& range) {
-  PluginURLFetcher* range_fetcher = new PluginURLFetcher(
-      this, url_, plugin_url_fetcher_->first_party_for_cookies(), "GET", NULL,
-      0, plugin_url_fetcher_->referrer(), range, false, false,
-      plugin_url_fetcher_->origin_pid(),
-      plugin_url_fetcher_->render_frame_id(),
-      plugin_url_fetcher_->render_view_id(), id_,
-      plugin_url_fetcher_->copy_stream_data());
-  range_request_fetchers_.push_back(range_fetcher);
-}
-
-bool PluginStreamUrl::Close(NPReason reason) {
-  // Protect the stream against it being destroyed or the whole plugin instance
-  // being destroyed within the destroy stream handler.
-  scoped_refptr<PluginStream> protect(this);
-  CancelRequest();
-  bool result = PluginStream::Close(reason);
-  instance()->RemoveStream(this);
-  return result;
-}
-
-WebPluginResourceClient* PluginStreamUrl::AsResourceClient() {
-  return static_cast<WebPluginResourceClient*>(this);
-}
-
-void PluginStreamUrl::CancelRequest() {
-  if (id_ > 0) {
-    if (plugin_url_fetcher_.get()) {
-      plugin_url_fetcher_->Cancel();
-    } else {
-      if (instance()->webplugin()) {
-        instance()->webplugin()->CancelResource(id_);
-      }
-    }
-    id_ = 0;
-  }
-  if (instance()->webplugin()) {
-    for (size_t i = 0; i < range_requests_.size(); ++i)
-      instance()->webplugin()->CancelResource(range_requests_[i]);
-  }
-
-  range_requests_.clear();
-
-  STLDeleteElements(&range_request_fetchers_);
-}
-
-void PluginStreamUrl::WillSendRequest(const GURL& url, int http_status_code) {
-  if (notify_needed()) {
-    // If the plugin participates in HTTP url redirect handling then notify it.
-    if (net::HttpResponseHeaders::IsRedirectResponseCode(http_status_code) &&
-        instance()->handles_url_redirects()) {
-      pending_redirect_url_ = url.spec();
-      instance()->NPP_URLRedirectNotify(url.spec().c_str(), http_status_code,
-          notify_data());
-      return;
-    }
-  }
-  url_ = url;
-  UpdateUrl(url.spec().c_str());
-}
-
-void PluginStreamUrl::DidReceiveResponse(const std::string& mime_type,
-                                         const std::string& headers,
-                                         uint32 expected_length,
-                                         uint32 last_modified,
-                                         bool request_is_seekable) {
-  // Protect the stream against it being destroyed or the whole plugin instance
-  // being destroyed within the new stream handler.
-  scoped_refptr<PluginStream> protect(this);
-
-  bool opened = Open(mime_type,
-                     headers,
-                     expected_length,
-                     last_modified,
-                     request_is_seekable);
-  if (!opened) {
-    CancelRequest();
-    instance()->RemoveStream(this);
-  } else {
-    SetDeferLoading(false);
-  }
-}
-
-void PluginStreamUrl::DidReceiveData(const char* buffer, int length,
-                                     int data_offset) {
-  if (!open())
-    return;
-
-  // Protect the stream against it being destroyed or the whole plugin instance
-  // being destroyed within the write handlers
-  scoped_refptr<PluginStream> protect(this);
-
-  if (length > 0) {
-    // The PluginStreamUrl instance could get deleted if the plugin fails to
-    // accept data in NPP_Write.
-    if (Write(const_cast<char*>(buffer), length, data_offset) > 0) {
-      SetDeferLoading(false);
-    }
-  }
-}
-
-void PluginStreamUrl::DidFinishLoading(unsigned long resource_id) {
-  if (!seekable()) {
-    Close(NPRES_DONE);
-  } else {
-    std::vector<unsigned long>::iterator it_resource = std::find(
-        range_requests_.begin(),
-        range_requests_.end(),
-        resource_id);
-    // Resource id must be known to us - either main resource id, or one
-    // of the resources, created for range requests.
-    DCHECK(resource_id == id_ || it_resource != range_requests_.end());
-    // We should notify the plugin about failed/finished requests to ensure
-    // that the number of active resource clients does not continue to grow.
-    if (instance()->webplugin())
-      instance()->webplugin()->CancelResource(resource_id);
-    if (it_resource != range_requests_.end())
-      range_requests_.erase(it_resource);
-  }
-}
-
-void PluginStreamUrl::DidFail(unsigned long resource_id) {
-  Close(NPRES_NETWORK_ERR);
-}
-
-bool PluginStreamUrl::IsMultiByteResponseExpected() {
-  return seekable();
-}
-
-int PluginStreamUrl::ResourceId() {
-  return id_;
-}
-
-PluginStreamUrl::~PluginStreamUrl() {
-  if (!plugin_url_fetcher_.get() && instance() && instance()->webplugin()) {
-    instance()->webplugin()->ResourceClientDeleted(AsResourceClient());
-  }
-
-  STLDeleteElements(&range_request_fetchers_);
-}
-
-void PluginStreamUrl::AddRangeRequestResourceId(unsigned long resource_id) {
-  DCHECK_NE(resource_id, 0u);
-  range_requests_.push_back(resource_id);
-}
-
-void PluginStreamUrl::SetDeferLoading(bool value) {
-  // If we determined that the request had failed via the HTTP headers in the
-  // response then we send out a failure notification to the plugin process, as
-  // certain plugins don't handle HTTP failure codes correctly.
-  if (plugin_url_fetcher_.get()) {
-    if (!value && plugin_url_fetcher_->pending_failure_notification()) {
-      // This object may be deleted now.
-      DidFail(id_);
-    }
-    return;
-  }
-  if (id_ > 0)
-    instance()->webplugin()->SetDeferResourceLoading(id_, value);
-  for (size_t i = 0; i < range_requests_.size(); ++i)
-    instance()->webplugin()->SetDeferResourceLoading(range_requests_[i],
-                                                     value);
-}
-
-void PluginStreamUrl::UpdateUrl(const char* url) {
-  DCHECK(!open());
-  free(const_cast<char*>(stream()->url));
-  stream()->url = base::strdup(url);
-  pending_redirect_url_.clear();
-}
-
-}  // namespace content
diff --git a/content/child/npapi/plugin_stream_url.h b/content/child/npapi/plugin_stream_url.h
deleted file mode 100644
index dea2fe4d..0000000
--- a/content/child/npapi/plugin_stream_url.h
+++ /dev/null
@@ -1,93 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_CHILD_NPAPI_PLUGIN_STREAM_URL_H_
-#define CONTENT_CHILD_NPAPI_PLUGIN_STREAM_URL_H_
-
-#include <vector>
-
-#include "base/memory/scoped_ptr.h"
-#include "content/child/npapi/plugin_stream.h"
-#include "content/child/npapi/webplugin_resource_client.h"
-#include "url/gurl.h"
-
-namespace content {
-class PluginInstance;
-class PluginURLFetcher;
-
-// A NPAPI Stream based on a URL.
-class PluginStreamUrl : public PluginStream,
-                        public WebPluginResourceClient {
- public:
-  // Create a new stream for sending to the plugin by fetching
-  // a URL. If notifyNeeded is set, then the plugin will be notified
-  // when the stream has been fully sent to the plugin.  Initialize
-  // must be called before the object is used.
-  PluginStreamUrl(unsigned long resource_id,
-                  const GURL &url,
-                  PluginInstance *instance,
-                  bool notify_needed,
-                  void *notify_data);
-
-  void SetPluginURLFetcher(PluginURLFetcher* fetcher);
-
-  void URLRedirectResponse(bool allow);
-
-  void FetchRange(const std::string& range);
-
-  // Stop sending the stream to the client.
-  // Overrides the base Close so we can cancel our fetching the URL if
-  // it is still loading.
-  bool Close(NPReason reason) override;
-  WebPluginResourceClient* AsResourceClient() override;
-  void CancelRequest() override;
-
-  // WebPluginResourceClient methods
-  void WillSendRequest(const GURL& url, int http_status_code) override;
-  void DidReceiveResponse(const std::string& mime_type,
-                          const std::string& headers,
-                          uint32 expected_length,
-                          uint32 last_modified,
-                          bool request_is_seekable) override;
-  void DidReceiveData(const char* buffer, int length, int data_offset) override;
-  void DidFinishLoading(unsigned long resource_id) override;
-  void DidFail(unsigned long resource_id) override;
-  bool IsMultiByteResponseExpected() override;
-  int ResourceId() override;
-  void AddRangeRequestResourceId(unsigned long resource_id) override;
-
- protected:
-  ~PluginStreamUrl() override;
-
- private:
-  void SetDeferLoading(bool value);
-
-  // In case of a redirect, this can be called to update the url.  But it must
-  // be called before Open().
-  void UpdateUrl(const char* url);
-
-  GURL url_;
-  unsigned long id_;
-
-  // Ids of additional resources requested via range requests issued on
-  // seekable streams.
-  // This is used when we're loading resources through the renderer, i.e. not
-  // using plugin_url_fetcher_.
-  std::vector<unsigned long> range_requests_;
-  // This is used when we're using plugin_url_fetcher_.
-  std::vector<PluginURLFetcher*> range_request_fetchers_;
-
-  // If the plugin participates in HTTP URL redirect handling then this member
-  // holds the url being redirected to while we wait for the plugin to make a
-  // decision on whether to allow or deny the redirect.
-  std::string pending_redirect_url_;
-
-  scoped_ptr<PluginURLFetcher> plugin_url_fetcher_;
-
-  DISALLOW_COPY_AND_ASSIGN(PluginStreamUrl);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_CHILD_NPAPI_PLUGIN_STREAM_URL_H_
diff --git a/content/child/npapi/plugin_stream_win.cc b/content/child/npapi/plugin_stream_win.cc
deleted file mode 100644
index af55f2f..0000000
--- a/content/child/npapi/plugin_stream_win.cc
+++ /dev/null
@@ -1,79 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/child/npapi/plugin_stream.h"
-
-#include "base/logging.h"
-#include "content/child/npapi/plugin_instance.h"
-
-namespace content {
-
-void PluginStream::ResetTempFileHandle() {
-  temp_file_handle_ = INVALID_HANDLE_VALUE;
-}
-
-void PluginStream::ResetTempFileName() {
-  temp_file_name_[0] = '\0';
-}
-
-void PluginStream::WriteAsFile() {
-  if (RequestedPluginModeIsAsFile())
-    instance_->NPP_StreamAsFile(&stream_, temp_file_name_);
-}
-
-size_t PluginStream::WriteBytes(const char *buf, size_t length) {
-  DWORD bytes;
-
-  if (!WriteFile(temp_file_handle_, buf, length, &bytes, 0))
-    return 0U;
-
-  return static_cast<size_t>(bytes);
-}
-
-bool PluginStream::OpenTempFile() {
-  DCHECK_EQ(INVALID_HANDLE_VALUE, temp_file_handle_);
-
-  // The reason for using all the Ascii versions of these filesystem
-  // calls is that the filename which we pass back to the plugin
-  // via NPAPI is an ascii filename.  Otherwise, we'd use wide-chars.
-  //
-  // TODO:
-  // This is a bug in NPAPI itself, and it needs to be fixed.
-  // The case which will fail is if a user has a multibyte name,
-  // but has the system locale set to english.  GetTempPathA will
-  // return junk in this case, causing us to be unable to open the
-  // file.
-
-  char temp_directory[MAX_PATH];
-  if (GetTempPathA(MAX_PATH, temp_directory) == 0)
-    return false;
-  if (GetTempFileNameA(temp_directory, "npstream", 0, temp_file_name_) == 0)
-    return false;
-  temp_file_handle_ = CreateFileA(temp_file_name_,
-                                  FILE_ALL_ACCESS,
-                                  FILE_SHARE_READ,
-                                  0,
-                                  CREATE_ALWAYS,
-                                  FILE_ATTRIBUTE_NORMAL,
-                                  0);
-  if (temp_file_handle_ == INVALID_HANDLE_VALUE) {
-    ResetTempFileName();
-    return false;
-  }
-  return true;
-}
-
-void PluginStream::CloseTempFile() {
-  if (!TempFileIsValid())
-    return;
-
-  CloseHandle(temp_file_handle_);
-  ResetTempFileHandle();
-}
-
-bool PluginStream::TempFileIsValid() const {
-  return temp_file_handle_ != INVALID_HANDLE_VALUE;
-}
-
-}  // namespace content
diff --git a/content/child/npapi/plugin_string_stream.cc b/content/child/npapi/plugin_string_stream.cc
deleted file mode 100644
index 15f38ad..0000000
--- a/content/child/npapi/plugin_string_stream.cc
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/child/npapi/plugin_string_stream.h"
-
-#include "url/gurl.h"
-
-namespace content {
-
-PluginStringStream::PluginStringStream(
-    PluginInstance* instance,
-    const GURL& url,
-    bool notify_needed,
-    void* notify_data)
-    : PluginStream(instance, url.spec().c_str(), notify_needed, notify_data) {
-}
-
-PluginStringStream::~PluginStringStream() {
-}
-
-void PluginStringStream::SendToPlugin(const std::string &data,
-                                      const std::string &mime_type) {
-  // Protect the stream against it being destroyed or the whole plugin instance
-  // being destroyed within the plugin stream callbacks.
-  scoped_refptr<PluginStringStream> protect(this);
-
-  int length = static_cast<int>(data.length());
-  if (Open(mime_type, std::string(), length, 0, false)) {
-    // TODO - check if it was not fully sent, and figure out a backup plan.
-    int written = Write(data.c_str(), length, 0);
-    NPReason reason = written == length ? NPRES_DONE : NPRES_NETWORK_ERR;
-    Close(reason);
-  }
-}
-
-}  // namespace content
diff --git a/content/child/npapi/plugin_string_stream.h b/content/child/npapi/plugin_string_stream.h
deleted file mode 100644
index 73dac44..0000000
--- a/content/child/npapi/plugin_string_stream.h
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_CHILD_NPAPI_PLUGIN_STRING_STREAM_H_
-#define CONTENT_CHILD_NPAPI_PLUGIN_STRING_STREAM_H_
-
-#include "content/child/npapi/plugin_stream.h"
-
-class GURL;
-
-namespace content {
-
-class PluginInstance;
-
-// An NPAPI stream from a string.
-class PluginStringStream : public PluginStream {
- public:
-  // Create a new stream for sending to the plugin.
-  // If notify_needed, will notify the plugin after the data has
-  // all been sent.
-  PluginStringStream(PluginInstance* instance,
-                     const GURL& url,
-                     bool notify_needed,
-                     void* notify_data);
-
-  // Initiates the sending of data to the plugin.
-  void SendToPlugin(const std::string& data,
-                    const std::string& mime_type);
-
- private:
-  ~PluginStringStream() override;
-
-  DISALLOW_COPY_AND_ASSIGN(PluginStringStream);
-};
-
-
-}  // namespace content
-
-#endif  // CONTENT_CHILD_NPAPI_PLUGIN_STRING_STREAM_H_
diff --git a/content/child/npapi/plugin_url_fetcher.cc b/content/child/npapi/plugin_url_fetcher.cc
deleted file mode 100644
index a307f68..0000000
--- a/content/child/npapi/plugin_url_fetcher.cc
+++ /dev/null
@@ -1,406 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/child/npapi/plugin_url_fetcher.h"
-
-#include "base/memory/scoped_ptr.h"
-#include "content/child/child_thread_impl.h"
-#include "content/child/multipart_response_delegate.h"
-#include "content/child/npapi/plugin_host.h"
-#include "content/child/npapi/plugin_instance.h"
-#include "content/child/npapi/plugin_stream_url.h"
-#include "content/child/npapi/webplugin.h"
-#include "content/child/npapi/webplugin_resource_client.h"
-#include "content/child/plugin_messages.h"
-#include "content/child/request_extra_data.h"
-#include "content/child/request_info.h"
-#include "content/child/resource_dispatcher.h"
-#include "content/child/web_url_loader_impl.h"
-#include "content/common/resource_request_body.h"
-#include "content/common/service_worker/service_worker_types.h"
-#include "content/public/common/resource_response_info.h"
-#include "net/base/load_flags.h"
-#include "net/base/net_errors.h"
-#include "net/http/http_response_headers.h"
-#include "net/url_request/redirect_info.h"
-#include "third_party/WebKit/public/platform/WebURLLoaderClient.h"
-#include "third_party/WebKit/public/platform/WebURLResponse.h"
-
-namespace content {
-namespace {
-
-// This class handles individual multipart responses. It is instantiated when
-// we receive HTTP status code 206 in the HTTP response. This indicates
-// that the response could have multiple parts each separated by a boundary
-// specified in the response header.
-// TODO(jam): this is similar to MultiPartResponseClient in webplugin_impl.cc,
-// we should remove that other class once we switch to loading from the plugin
-// process by default.
-class MultiPartResponseClient : public blink::WebURLLoaderClient {
- public:
-  explicit MultiPartResponseClient(PluginStreamUrl* plugin_stream)
-      : byte_range_lower_bound_(0), plugin_stream_(plugin_stream) {}
-
-  // blink::WebURLLoaderClient implementation:
-  void didReceiveResponse(blink::WebURLLoader* loader,
-                          const blink::WebURLResponse& response) override {
-    int64 byte_range_upper_bound, instance_size;
-    if (!MultipartResponseDelegate::ReadContentRanges(response,
-                                                      &byte_range_lower_bound_,
-                                                      &byte_range_upper_bound,
-                                                      &instance_size)) {
-      NOTREACHED();
-    }
-  }
-  void didReceiveData(blink::WebURLLoader* loader,
-                      const char* data,
-                      int data_length,
-                      int encoded_data_length) override {
-    // TODO(ananta)
-    // We should defer further loads on multipart resources on the same lines
-    // as regular resources requested by plugins to prevent reentrancy.
-    int64 data_offset = byte_range_lower_bound_;
-    byte_range_lower_bound_ += data_length;
-    plugin_stream_->DidReceiveData(data, data_length, data_offset);
-    // DANGER: this instance may be deleted at this point.
-  }
-
- private:
-  // The lower bound of the byte range.
-  int64 byte_range_lower_bound_;
-  // The handler for the data.
-  PluginStreamUrl* plugin_stream_;
-};
-
-}  // namespace
-
-PluginURLFetcher::PluginURLFetcher(PluginStreamUrl* plugin_stream,
-                                   const GURL& url,
-                                   const GURL& first_party_for_cookies,
-                                   const std::string& method,
-                                   const char* buf,
-                                   unsigned int len,
-                                   const Referrer& referrer,
-                                   const std::string& range,
-                                   bool notify_redirects,
-                                   bool is_plugin_src_load,
-                                   int origin_pid,
-                                   int render_frame_id,
-                                   int render_view_id,
-                                   unsigned long resource_id,
-                                   bool copy_stream_data)
-    : plugin_stream_(plugin_stream),
-      url_(url),
-      first_party_for_cookies_(first_party_for_cookies),
-      referrer_(referrer),
-      notify_redirects_(notify_redirects),
-      is_plugin_src_load_(is_plugin_src_load),
-      origin_pid_(origin_pid),
-      render_frame_id_(render_frame_id),
-      render_view_id_(render_view_id),
-      resource_id_(resource_id),
-      copy_stream_data_(copy_stream_data),
-      data_offset_(0),
-      pending_failure_notification_(false),
-      request_id_(-1),
-      weak_factory_(this) {
-  RequestInfo request_info;
-  request_info.method = method;
-  request_info.url = url;
-  request_info.first_party_for_cookies = first_party_for_cookies;
-  request_info.referrer = referrer;
-  request_info.load_flags = net::LOAD_NORMAL;
-  request_info.requestor_pid = origin_pid;
-  request_info.request_type = RESOURCE_TYPE_OBJECT;
-  request_info.routing_id = render_view_id;
-  // ServiceWorker is disabled for NPAPI.
-  request_info.skip_service_worker = true;
-
-  RequestExtraData extra_data;
-  extra_data.set_render_frame_id(render_frame_id);
-  extra_data.set_is_main_frame(false);
-  request_info.extra_data = &extra_data;
-
-  std::vector<char> body;
-  if (method == "POST") {
-    bool content_type_found = false;
-    std::vector<std::string> names;
-    std::vector<std::string> values;
-    PluginHost::SetPostData(buf, len, &names, &values, &body);
-    for (size_t i = 0; i < names.size(); ++i) {
-      if (!request_info.headers.empty())
-        request_info.headers += "\r\n";
-      request_info.headers += names[i] + ": " + values[i];
-      if (base::LowerCaseEqualsASCII(names[i], "content-type"))
-        content_type_found = true;
-    }
-
-    if (!content_type_found) {
-      if (!request_info.headers.empty())
-        request_info.headers += "\r\n";
-      request_info.headers += "Content-Type: application/x-www-form-urlencoded";
-    }
-  } else {
-    if (!range.empty())
-      request_info.headers = std::string("Range: ") + range;
-  }
-
-  scoped_refptr<ResourceRequestBody> request_body = new ResourceRequestBody;
-  if (!body.empty())
-    request_body->AppendBytes(&body[0], body.size());
-
-  request_id_ = ChildThreadImpl::current()->resource_dispatcher()->StartAsync(
-      request_info, request_body.get(), this);
-
-  // TODO(jam): range requests
-}
-
-PluginURLFetcher::~PluginURLFetcher() {
-  if (request_id_ >= 0) {
-    ChildThreadImpl::current()->resource_dispatcher()->RemovePendingRequest(
-        request_id_);
-  }
-}
-
-void PluginURLFetcher::Cancel() {
-  ChildThreadImpl::current()->resource_dispatcher()->Cancel(request_id_);
-
-  // Due to races and nested event loops, PluginURLFetcher may still receive
-  // events from the bridge before being destroyed. Do not forward additional
-  // events back to the plugin, via either |plugin_stream_| or
-  // |multipart_delegate_| which has its own pointer via
-  // MultiPartResponseClient.
-  if (multipart_delegate_)
-    multipart_delegate_->Cancel();
-  plugin_stream_ = NULL;
-}
-
-void PluginURLFetcher::URLRedirectResponse(bool allow) {
-  if (!plugin_stream_)
-    return;
-
-  if (allow) {
-    ChildThreadImpl::current()->resource_dispatcher()->SetDefersLoading(
-        request_id_, false);
-  } else {
-    ChildThreadImpl::current()->resource_dispatcher()->Cancel(request_id_);
-    plugin_stream_->DidFail(resource_id_);  // That will delete |this|.
-  }
-}
-
-void PluginURLFetcher::OnUploadProgress(uint64 position, uint64 size) {
-}
-
-bool PluginURLFetcher::OnReceivedRedirect(
-    const net::RedirectInfo& redirect_info,
-    const ResourceResponseInfo& info) {
-  if (!plugin_stream_)
-    return false;
-
-  // TODO(jam): THIS LOGIC IS COPIED FROM WebPluginImpl::willSendRequest until
-  // kDirectNPAPIRequests is the default and we can remove the old path there.
-
-  // Currently this check is just to catch an https -> http redirect when
-  // loading the main plugin src URL. Longer term, we could investigate
-  // firing mixed diplay or scripting issues for subresource loads
-  // initiated by plugins.
-  if (is_plugin_src_load_ &&
-      !plugin_stream_->instance()->webplugin()->CheckIfRunInsecureContent(
-          redirect_info.new_url)) {
-    plugin_stream_->DidFail(resource_id_);  // That will delete |this|.
-    return false;
-  }
-
-  GURL old_url = url_;
-  url_ = redirect_info.new_url;
-  first_party_for_cookies_ = redirect_info.new_first_party_for_cookies;
-
-  // If the plugin does not participate in url redirect notifications then just
-  // block cross origin 307 POST redirects.
-  if (!notify_redirects_) {
-    if (redirect_info.status_code == 307 &&
-        redirect_info.new_method == "POST" &&
-        old_url.GetOrigin() != url_.GetOrigin()) {
-      plugin_stream_->DidFail(resource_id_);  // That will delete |this|.
-      return false;
-    }
-  } else {
-    // Pause the request while we ask the plugin what to do about the redirect.
-    ChildThreadImpl::current()->resource_dispatcher()->SetDefersLoading(
-        request_id_, true);
-    plugin_stream_->WillSendRequest(url_, redirect_info.status_code);
-  }
-
-  return true;
-}
-
-void PluginURLFetcher::OnReceivedResponse(const ResourceResponseInfo& info) {
-  if (!plugin_stream_)
-    return;
-
-  // TODO(jam): THIS LOGIC IS COPIED FROM WebPluginImpl::didReceiveResponse
-  // GetAllHeaders, and GetResponseInfo until kDirectNPAPIRequests is the
-  // default and we can remove the old path there.
-
-  bool request_is_seekable = true;
-  DCHECK(!multipart_delegate_.get());
-  if (plugin_stream_->seekable()) {
-    int response_code = info.headers->response_code();
-    if (response_code == 206) {
-      blink::WebURLResponse response;
-      response.initialize();
-      WebURLLoaderImpl::PopulateURLResponse(url_, info, &response,
-                                            false /* report_security_info */);
-
-      std::string multipart_boundary;
-      if (MultipartResponseDelegate::ReadMultipartBoundary(
-              response, &multipart_boundary)) {
-        plugin_stream_->instance()->webplugin()->DidStartLoading();
-
-        MultiPartResponseClient* multi_part_response_client =
-            new MultiPartResponseClient(plugin_stream_);
-
-        multipart_delegate_.reset(new MultipartResponseDelegate(
-            multi_part_response_client, NULL, response, multipart_boundary));
-
-        // Multiple ranges requested, data will be delivered by
-        // MultipartResponseDelegate.
-        data_offset_ = 0;
-        return;
-      }
-
-      int64 upper_bound = 0, instance_size = 0;
-      // Single range requested - go through original processing for
-      // non-multipart requests, but update data offset.
-      MultipartResponseDelegate::ReadContentRanges(
-          response, &data_offset_, &upper_bound, &instance_size);
-    } else if (response_code == 200) {
-      // TODO: should we handle this case? We used to but it's not clear that we
-      // still need to. This was bug 5403, fixed in r7139.
-    }
-  }
-
-  // If the length comes in as -1, then it indicates that it was not
-  // read off the HTTP headers. We replicate Safari webkit behavior here,
-  // which is to set it to 0.
-  int expected_length = std::max(static_cast<int>(info.content_length), 0);
-
-  base::Time temp;
-  uint32 last_modified = 0;
-  std::string headers;
-  if (info.headers.get()) {  // NULL for data: urls.
-    if (info.headers->GetLastModifiedValue(&temp))
-      last_modified = static_cast<uint32>(temp.ToDoubleT());
-
-     // TODO(darin): Shouldn't we also report HTTP version numbers?
-    int response_code = info.headers->response_code();
-    headers = base::StringPrintf("HTTP %d ", response_code);
-    headers += info.headers->GetStatusText();
-    headers += "\n";
-
-    void* iter = NULL;
-    std::string name, value;
-    while (info.headers->EnumerateHeaderLines(&iter, &name, &value)) {
-      // TODO(darin): Should we really exclude headers with an empty value?
-      if (!name.empty() && !value.empty())
-        headers += name + ": " + value + "\n";
-    }
-
-    // Bug http://b/issue?id=925559. The flash plugin would not handle the HTTP
-    // error codes in the stream header and as a result, was unaware of the fate
-    // of the HTTP requests issued via NPN_GetURLNotify. Webkit and FF destroy
-    // the stream and invoke the NPP_DestroyStream function on the plugin if the
-    // HTTPrequest fails.
-    if ((url_.SchemeIs(url::kHttpScheme) || url_.SchemeIs(url::kHttpsScheme)) &&
-        (response_code < 100 || response_code >= 400)) {
-      pending_failure_notification_ = true;
-    }
-  }
-
-  plugin_stream_->DidReceiveResponse(info.mime_type,
-                                     headers,
-                                     expected_length,
-                                     last_modified,
-                                     request_is_seekable);
-}
-
-void PluginURLFetcher::OnDownloadedData(int len,
-                                        int encoded_data_length) {
-}
-
-void PluginURLFetcher::OnReceivedData(scoped_ptr<ReceivedData> data) {
-  const char* payload = data->payload();
-  int data_length = data->length();
-  int encoded_data_length = data->encoded_length();
-  if (!plugin_stream_)
-    return;
-
-  if (multipart_delegate_) {
-    multipart_delegate_->OnReceivedData(payload, data_length,
-                                        encoded_data_length);
-  } else {
-    int64 offset = data_offset_;
-    data_offset_ += data_length;
-
-    if (copy_stream_data_) {
-      // QuickTime writes to this memory, and since we got it from
-      // ResourceDispatcher it's not mapped for write access in this process.
-      // http://crbug.com/308466.
-      scoped_ptr<char[]> data_copy(new char[data_length]);
-      memcpy(data_copy.get(), payload, data_length);
-      plugin_stream_->DidReceiveData(data_copy.get(), data_length, offset);
-    } else {
-      plugin_stream_->DidReceiveData(payload, data_length, offset);
-    }
-    // DANGER: this instance may be deleted at this point.
-  }
-}
-
-void PluginURLFetcher::OnCompletedRequest(
-    int error_code,
-    bool was_ignored_by_handler,
-    bool stale_copy_in_cache,
-    const std::string& security_info,
-    const base::TimeTicks& completion_time,
-    int64 total_transfer_size) {
-  if (!plugin_stream_)
-    return;
-
-  if (multipart_delegate_) {
-    multipart_delegate_->OnCompletedRequest();
-    multipart_delegate_.reset();
-  }
-
-  if (error_code == net::OK) {
-    plugin_stream_->DidFinishLoading(resource_id_);
-  } else {
-    plugin_stream_->DidFail(resource_id_);
-  }
-}
-
-void PluginURLFetcher::OnReceivedCompletedResponse(
-    const content::ResourceResponseInfo& info,
-    scoped_ptr<ReceivedData> data,
-    int error_code,
-    bool was_ignored_by_handler,
-    bool stale_copy_in_cache,
-    const std::string& security_info,
-    const base::TimeTicks& completion_time,
-    int64 total_transfer_size) {
-  // |this| can be deleted on each callback. |weak_this| is placed here to
-  // detect the deletion.
-  base::WeakPtr<PluginURLFetcher> weak_this = weak_factory_.GetWeakPtr();
-  OnReceivedResponse(info);
-
-  if (!weak_this)
-    return;
-  if (data)
-    OnReceivedData(data.Pass());
-
-  if (!weak_this)
-    return;
-  OnCompletedRequest(error_code, was_ignored_by_handler, stale_copy_in_cache,
-                     security_info, completion_time, total_transfer_size);
-}
-}  // namespace content
diff --git a/content/child/npapi/plugin_url_fetcher.h b/content/child/npapi/plugin_url_fetcher.h
deleted file mode 100644
index 8b0f09a..0000000
--- a/content/child/npapi/plugin_url_fetcher.h
+++ /dev/null
@@ -1,102 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_CHILD_NPAPI_PLUGIN_URL_FETCHER_H_
-#define CONTENT_CHILD_NPAPI_PLUGIN_URL_FETCHER_H_
-
-#include <string>
-
-#include "base/memory/scoped_ptr.h"
-#include "base/memory/weak_ptr.h"
-#include "content/public/child/request_peer.h"
-#include "content/public/common/referrer.h"
-#include "url/gurl.h"
-
-namespace content {
-class MultipartResponseDelegate;
-class PluginStreamUrl;
-
-// Fetches URLS for a plugin using ResourceDispatcher.
-class PluginURLFetcher : public RequestPeer {
- public:
-  PluginURLFetcher(PluginStreamUrl* plugin_stream,
-                   const GURL& url,
-                   const GURL& first_party_for_cookies,
-                   const std::string& method,
-                   const char* buf,
-                   unsigned int len,
-                   const Referrer& referrer,
-                   const std::string& range,
-                   bool notify_redirects,
-                   bool is_plugin_src_load,
-                   int origin_pid,
-                   int render_frame_id,
-                   int render_view_id,
-                   unsigned long resource_id,
-                   bool copy_stream_data);
-  ~PluginURLFetcher() override;
-
-  // Cancels the current request.
-  void Cancel();
-
-  // Called with the plugin's reply to NPP_URLRedirectNotify.
-  void URLRedirectResponse(bool allow);
-
-  GURL first_party_for_cookies() { return first_party_for_cookies_; }
-  Referrer referrer() { return referrer_; }
-  int origin_pid() { return origin_pid_; }
-  int render_frame_id() { return render_frame_id_; }
-  int render_view_id() { return render_view_id_; }
-  bool copy_stream_data() { return copy_stream_data_; }
-  bool pending_failure_notification() { return pending_failure_notification_; }
-
- private:
-  // RequestPeer implementation:
-  void OnUploadProgress(uint64 position, uint64 size) override;
-  bool OnReceivedRedirect(const net::RedirectInfo& redirect_info,
-                          const ResourceResponseInfo& info) override;
-  void OnReceivedResponse(const ResourceResponseInfo& info) override;
-  void OnDownloadedData(int len, int encoded_data_length) override;
-  void OnReceivedData(scoped_ptr<ReceivedData> data) override;
-  void OnCompletedRequest(int error_code,
-                          bool was_ignored_by_handler,
-                          bool stale_copy_in_cache,
-                          const std::string& security_info,
-                          const base::TimeTicks& completion_time,
-                          int64 total_transfer_size) override;
-  void OnReceivedCompletedResponse(const ResourceResponseInfo& info,
-                                   scoped_ptr<ReceivedData> data,
-                                   int error_code,
-                                   bool was_ignored_by_handler,
-                                   bool stale_copy_in_cache,
-                                   const std::string& security_info,
-                                   const base::TimeTicks& completion_time,
-                                   int64 total_transfer_size) override;
-
-  // |plugin_stream_| becomes NULL after Cancel() to ensure no further calls
-  // |reach it.
-  PluginStreamUrl* plugin_stream_;
-  GURL url_;
-  GURL first_party_for_cookies_;
-  Referrer referrer_;
-  bool notify_redirects_;
-  bool is_plugin_src_load_;
-  int origin_pid_;
-  int render_frame_id_;
-  int render_view_id_;
-  unsigned long resource_id_;
-  bool copy_stream_data_;
-  int64 data_offset_;
-  bool pending_failure_notification_;
-  int request_id_;
-
-  scoped_ptr<MultipartResponseDelegate> multipart_delegate_;
-  base::WeakPtrFactory<PluginURLFetcher> weak_factory_;
-
-  DISALLOW_COPY_AND_ASSIGN(PluginURLFetcher);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_CHILD_NPAPI_PLUGIN_URL_FETCHER_H_
diff --git a/content/child/npapi/webplugin.h b/content/child/npapi/webplugin.h
index c1281f1..13466ea 100644
--- a/content/child/npapi/webplugin.h
+++ b/content/child/npapi/webplugin.h
@@ -70,26 +70,9 @@
   virtual std::string GetCookies(const GURL& url,
                                  const GURL& first_party_for_cookies) = 0;
 
-  // Handles GetURL/GetURLNotify/PostURL/PostURLNotify requests initiated
-  // by plugins.  If the plugin wants notification of the result, notify_id will
-  // be non-zero.
-  virtual void HandleURLRequest(const char* url,
-                                const char* method,
-                                const char* target,
-                                const char* buf,
-                                unsigned int len,
-                                int notify_id,
-                                bool popups_allowed,
-                                bool notify_redirects) = 0;
-
   // Cancels document load.
   virtual void CancelDocumentLoad() = 0;
 
-  // Initiates a HTTP range request for an existing stream.
-  virtual void InitiateHTTPRangeRequest(const char* url,
-                                        const char* range_info,
-                                        int range_request_id) = 0;
-
   virtual void DidStartLoading() = 0;
   virtual void DidStopLoading() = 0;
 
diff --git a/content/child/npapi/webplugin_delegate.h b/content/child/npapi/webplugin_delegate.h
index 8f13c8d..c18eb76 100644
--- a/content/child/npapi/webplugin_delegate.h
+++ b/content/child/npapi/webplugin_delegate.h
@@ -87,65 +87,8 @@
   // Returns false if the value is not available.
   virtual bool GetFormValue(base::string16* value) = 0;
 
-  // Receives notification about a resource load that the plugin initiated
-  // for a frame.
-  virtual void DidFinishLoadWithReason(const GURL& url, NPReason reason,
-                                       int notify_id) = 0;
-
   // Returns the process id of the process that is running the plugin.
   virtual int GetProcessId() = 0;
-
-  // The result, UTF-8 encoded, of the script execution is returned via this
-  // function.
-  virtual void SendJavaScriptStream(const GURL& url,
-                                    const std::string& result,
-                                    bool success,
-                                    int notify_id) = 0;
-
-  // Receives notification about data being available.
-  virtual void DidReceiveManualResponse(const GURL& url,
-                                        const std::string& mime_type,
-                                        const std::string& headers,
-                                        uint32 expected_length,
-                                        uint32 last_modified) = 0;
-
-  // Receives the data.
-  virtual void DidReceiveManualData(const char* buffer, int length) = 0;
-
-  // Indicates end of data load.
-  virtual void DidFinishManualLoading() = 0;
-
-  // Indicates a failure in data receipt.
-  virtual void DidManualLoadFail() = 0;
-
-  // Creates a WebPluginResourceClient instance and returns the same.
-  virtual WebPluginResourceClient* CreateResourceClient(
-      unsigned long resource_id,
-      const GURL& url,
-      int notify_id) = 0;
-
-  // Creates a WebPluginResourceClient instance for an existing stream that is
-  // has become seekable.
-  virtual WebPluginResourceClient* CreateSeekableResourceClient(
-      unsigned long resource_id, int range_request_id) = 0;
-
-  // Tell the plugin that the given URL should be fetched. This is a result of
-  // loading the plugin data or the plugin calling HandleURLRequest which didn't
-  // end up being routed to another frame or being a javscript:// URL.
-  virtual void FetchURL(unsigned long resource_id,
-                        int notify_id,
-                        const GURL& url,
-                        const GURL& first_party_for_cookies,
-                        const std::string& method,
-                        const char* buf,
-                        unsigned int len,
-                        const Referrer& referrer,
-                        bool notify_redirects,
-                        bool is_plugin_src_load,
-                        int origin_pid,
-                        int render_frame_id,
-                        int render_view_id) = 0;
-
 };
 
 }  // namespace content
diff --git a/content/child/npapi/webplugin_delegate_impl.cc b/content/child/npapi/webplugin_delegate_impl.cc
index 18149c3..8323bc8 100644
--- a/content/child/npapi/webplugin_delegate_impl.cc
+++ b/content/child/npapi/webplugin_delegate_impl.cc
@@ -14,8 +14,6 @@
 #include "base/strings/utf_string_conversions.h"
 #include "content/child/npapi/plugin_instance.h"
 #include "content/child/npapi/plugin_lib.h"
-#include "content/child/npapi/plugin_stream_url.h"
-#include "content/child/npapi/plugin_url_fetcher.h"
 #include "third_party/WebKit/public/web/WebInputEvent.h"
 
 using blink::WebCursorInfo;
@@ -102,12 +100,6 @@
 
 void WebPluginDelegateImpl::DestroyInstance() {
   if (instance_.get() && (instance_->npp()->ndata != NULL)) {
-    // Shutdown all streams before destroying so that
-    // no streams are left "in progress".  Need to do
-    // this before calling set_web_plugin(NULL) because the
-    // instance uses the helper to do the download.
-    instance_->CloseStreams();
-
     window_.window = NULL;
     if (creation_succeeded_ &&
         !(quirks_ & PLUGIN_QUIRK_DONT_SET_NULL_WINDOW_HANDLE_ON_DESTROY)) {
@@ -193,56 +185,11 @@
   return instance_->GetFormValue(value);
 }
 
-void WebPluginDelegateImpl::DidFinishLoadWithReason(const GURL& url,
-                                                    NPReason reason,
-                                                    int notify_id) {
-  if (quirks_ & PLUGIN_QUIRK_ALWAYS_NOTIFY_SUCCESS &&
-      reason == NPRES_NETWORK_ERR) {
-    // Flash needs this or otherwise it unloads the launching swf object.
-    reason = NPRES_DONE;
-  }
-
-  instance()->DidFinishLoadWithReason(url, reason, notify_id);
-}
-
 int WebPluginDelegateImpl::GetProcessId() {
   // We are in process, so the plugin pid is this current process pid.
   return base::GetCurrentProcId();
 }
 
-void WebPluginDelegateImpl::SendJavaScriptStream(const GURL& url,
-                                                 const std::string& result,
-                                                 bool success,
-                                                 int notify_id) {
-  instance()->SendJavaScriptStream(url, result, success, notify_id);
-}
-
-void WebPluginDelegateImpl::DidReceiveManualResponse(
-    const GURL& url, const std::string& mime_type,
-    const std::string& headers, uint32 expected_length, uint32 last_modified) {
-  if (!windowless_) {
-    // Calling NPP_WriteReady before NPP_SetWindow causes movies to not load in
-    // Flash.  See http://b/issue?id=892174.
-    DCHECK(windowed_did_set_window_);
-  }
-
-  instance()->DidReceiveManualResponse(url, mime_type, headers,
-                                       expected_length, last_modified);
-}
-
-void WebPluginDelegateImpl::DidReceiveManualData(const char* buffer,
-                                                 int length) {
-  instance()->DidReceiveManualData(buffer, length);
-}
-
-void WebPluginDelegateImpl::DidFinishManualLoading() {
-  instance()->DidFinishManualLoading();
-}
-
-void WebPluginDelegateImpl::DidManualLoadFail() {
-  instance()->DidManualLoadFail();
-}
-
 base::FilePath WebPluginDelegateImpl::GetPluginPath() {
   return instance()->plugin_lib()->plugin_info().path;
 }
@@ -289,44 +236,4 @@
   }
 }
 
-WebPluginResourceClient* WebPluginDelegateImpl::CreateResourceClient(
-    unsigned long resource_id, const GURL& url, int notify_id) {
-  return instance()->CreateStream(
-      resource_id, url, std::string(), notify_id);
-}
-
-WebPluginResourceClient* WebPluginDelegateImpl::CreateSeekableResourceClient(
-    unsigned long resource_id, int range_request_id) {
-  WebPluginResourceClient* resource_client = instance()->GetRangeRequest(
-      range_request_id);
-  if (resource_client)
-    resource_client->AddRangeRequestResourceId(resource_id);
-  return resource_client;
-}
-
-void WebPluginDelegateImpl::FetchURL(unsigned long resource_id,
-                                     int notify_id,
-                                     const GURL& url,
-                                     const GURL& first_party_for_cookies,
-                                     const std::string& method,
-                                     const char* buf,
-                                     unsigned int len,
-                                     const Referrer& referrer,
-                                     bool notify_redirects,
-                                     bool is_plugin_src_load,
-                                     int origin_pid,
-                                     int render_frame_id,
-                                     int render_view_id) {
-  // TODO(jam): once we switch over to resource loading always happening in this
-  // code path, remove WebPluginResourceClient abstraction.
-  PluginStreamUrl* plugin_stream = instance()->CreateStream(
-      resource_id, url, std::string(), notify_id);
-
-  bool copy_stream_data = !!(quirks_ & PLUGIN_QUIRK_COPY_STREAM_DATA);
-  plugin_stream->SetPluginURLFetcher(new PluginURLFetcher(
-      plugin_stream, url, first_party_for_cookies, method, buf, len,
-      referrer, std::string(), notify_redirects, is_plugin_src_load, origin_pid,
-      render_frame_id, render_view_id, resource_id, copy_stream_data));
-}
-
 }  // namespace content
diff --git a/content/child/npapi/webplugin_delegate_impl.h b/content/child/npapi/webplugin_delegate_impl.h
index 72f559a9..9d75082 100644
--- a/content/child/npapi/webplugin_delegate_impl.h
+++ b/content/child/npapi/webplugin_delegate_impl.h
@@ -92,41 +92,7 @@
   NPObject* GetPluginScriptableObject() override;
   NPP GetPluginNPP() override;
   bool GetFormValue(base::string16* value) override;
-  void DidFinishLoadWithReason(const GURL& url,
-                               NPReason reason,
-                               int notify_id) override;
   int GetProcessId() override;
-  void SendJavaScriptStream(const GURL& url,
-                            const std::string& result,
-                            bool success,
-                            int notify_id) override;
-  void DidReceiveManualResponse(const GURL& url,
-                                const std::string& mime_type,
-                                const std::string& headers,
-                                uint32 expected_length,
-                                uint32 last_modified) override;
-  void DidReceiveManualData(const char* buffer, int length) override;
-  void DidFinishManualLoading() override;
-  void DidManualLoadFail() override;
-  WebPluginResourceClient* CreateResourceClient(unsigned long resource_id,
-                                                const GURL& url,
-                                                int notify_id) override;
-  WebPluginResourceClient* CreateSeekableResourceClient(
-      unsigned long resource_id,
-      int range_request_id) override;
-  void FetchURL(unsigned long resource_id,
-                int notify_id,
-                const GURL& url,
-                const GURL& first_party_for_cookies,
-                const std::string& method,
-                const char* buf,
-                unsigned int len,
-                const Referrer& referrer,
-                bool notify_redirects,
-                bool is_plugin_src_load,
-                int origin_pid,
-                int render_frame_id,
-                int render_view_id) override;
   // End of WebPluginDelegate implementation.
 
   gfx::PluginWindowHandle windowed_handle() const { return windowed_handle_; }
diff --git a/content/child/npapi/webplugin_delegate_impl_win.cc b/content/child/npapi/webplugin_delegate_impl_win.cc
index d64af01c..8dd3687 100644
--- a/content/child/npapi/webplugin_delegate_impl_win.cc
+++ b/content/child/npapi/webplugin_delegate_impl_win.cc
@@ -23,7 +23,6 @@
 #include "base/win/windows_version.h"
 #include "content/child/npapi/plugin_instance.h"
 #include "content/child/npapi/plugin_lib.h"
-#include "content/child/npapi/plugin_stream_url.h"
 #include "content/child/npapi/webplugin.h"
 #include "content/child/npapi/webplugin_ime_win.h"
 #include "content/common/cursors/webcursor.h"
diff --git a/content/child/npapi/webplugin_resource_client.h b/content/child/npapi/webplugin_resource_client.h
index fc392649..9604f60 100644
--- a/content/child/npapi/webplugin_resource_client.h
+++ b/content/child/npapi/webplugin_resource_client.h
@@ -32,7 +32,6 @@
   // is cleared. This applies for seekable streams.
   virtual void DidFinishLoading(unsigned long resource_id) = 0;
   virtual void DidFail(unsigned long resource_id) = 0;
-  virtual bool IsMultiByteResponseExpected() = 0;
   virtual int ResourceId() = 0;
   // Tells this object that it will get responses from multiple resources.
   // This is necessary since the plugin process uses a single instance of
diff --git a/content/child/plugin_messages.h b/content/child/plugin_messages.h
index 25d4545..f742338 100644
--- a/content/child/plugin_messages.h
+++ b/content/child/plugin_messages.h
@@ -34,16 +34,6 @@
   IPC_STRUCT_MEMBER(int, host_render_view_routing_id)
 IPC_STRUCT_END()
 
-IPC_STRUCT_BEGIN(PluginHostMsg_URLRequest_Params)
-  IPC_STRUCT_MEMBER(std::string, url)
-  IPC_STRUCT_MEMBER(std::string, method)
-  IPC_STRUCT_MEMBER(std::string, target)
-  IPC_STRUCT_MEMBER(std::vector<char>, buffer)
-  IPC_STRUCT_MEMBER(int, notify_id)
-  IPC_STRUCT_MEMBER(bool, popups_allowed)
-  IPC_STRUCT_MEMBER(bool, notify_redirects)
-IPC_STRUCT_END()
-
 IPC_STRUCT_BEGIN(PluginMsg_DidReceiveResponseParams)
   IPC_STRUCT_MEMBER(unsigned long, id)
   IPC_STRUCT_MEMBER(std::string, mime_type)
@@ -55,7 +45,6 @@
 
 IPC_STRUCT_BEGIN(PluginMsg_FetchURL_Params)
   IPC_STRUCT_MEMBER(unsigned long, resource_id)
-  IPC_STRUCT_MEMBER(int, notify_id)
   IPC_STRUCT_MEMBER(GURL, url)
   IPC_STRUCT_MEMBER(GURL, first_party_for_cookies)
   IPC_STRUCT_MEMBER(std::string, method)
@@ -116,11 +105,6 @@
                            base::string16 /* value */,
                            bool /* success */)
 
-IPC_MESSAGE_ROUTED3(PluginMsg_DidFinishLoadWithReason,
-                    GURL /* url */,
-                    int /* reason */,
-                    int /* notify_id */)
-
 // Updates the plugin location.
 IPC_MESSAGE_ROUTED1(PluginMsg_UpdateGeometry,
                     PluginMsg_UpdateGeometry_Param)
@@ -159,44 +143,12 @@
 IPC_MESSAGE_ROUTED1(PluginMsg_DidFail,
                     unsigned long /* id */)
 
-IPC_MESSAGE_ROUTED4(PluginMsg_SendJavaScriptStream,
-                    GURL /* url */,
-                    std::string /* result */,
-                    bool /* success */,
-                    int /* notify_id */)
-
-IPC_MESSAGE_ROUTED2(PluginMsg_DidReceiveManualResponse,
-                    GURL /* url */,
-                    PluginMsg_DidReceiveResponseParams)
-
-IPC_MESSAGE_ROUTED1(PluginMsg_DidReceiveManualData,
-                    std::vector<char> /* buffer */)
-
-IPC_MESSAGE_ROUTED0(PluginMsg_DidFinishManualLoading)
-
-IPC_MESSAGE_ROUTED0(PluginMsg_DidManualLoadFail)
-
-IPC_MESSAGE_ROUTED3(PluginMsg_HandleURLRequestReply,
-                    unsigned long /* resource_id */,
-                    GURL /* url */,
-                    int /* notify_id */)
-
-IPC_MESSAGE_ROUTED2(PluginMsg_HTTPRangeRequestReply,
-                    unsigned long /* resource_id */,
-                    int /* range_request_id */)
-
 IPC_MESSAGE_CONTROL1(PluginMsg_SignalModalDialogEvent,
                      int /* render_view_id */)
 
 IPC_MESSAGE_CONTROL1(PluginMsg_ResetModalDialogEvent,
                      int /* render_view_id */)
 
-IPC_MESSAGE_ROUTED1(PluginMsg_FetchURL,
-                    PluginMsg_FetchURL_Params)
-
-IPC_MESSAGE_CONTROL1(PluginHostMsg_DidAbortLoading,
-                     int /* render_view_id */)
-
 #if defined(OS_WIN)
 IPC_MESSAGE_ROUTED4(PluginMsg_ImeCompositionUpdated,
                     base::string16 /* text */,
@@ -237,9 +189,6 @@
 IPC_SYNC_MESSAGE_ROUTED1_0(PluginHostMsg_SetWindow,
                            gfx::PluginWindowHandle /* window */)
 
-IPC_MESSAGE_ROUTED1(PluginHostMsg_URLRequest,
-                    PluginHostMsg_URLRequest_Params)
-
 IPC_MESSAGE_ROUTED1(PluginHostMsg_CancelResource,
                     int /* id */)
 
@@ -271,11 +220,6 @@
 
 IPC_MESSAGE_ROUTED0(PluginHostMsg_CancelDocumentLoad)
 
-IPC_MESSAGE_ROUTED3(PluginHostMsg_InitiateHTTPRangeRequest,
-                    std::string /* url */,
-                    std::string /* range_info */,
-                    int         /* range_request_id */)
-
 IPC_MESSAGE_ROUTED0(PluginHostMsg_DidStartLoading)
 IPC_MESSAGE_ROUTED0(PluginHostMsg_DidStopLoading)
 
diff --git a/content/child/runtime_features.cc b/content/child/runtime_features.cc
index 3cdaf40..be71402 100644
--- a/content/child/runtime_features.cc
+++ b/content/child/runtime_features.cc
@@ -185,9 +185,6 @@
   if (command_line.HasSwitch(switches::kReducedReferrerGranularity))
     WebRuntimeFeatures::enableReducedReferrerGranularity(true);
 
-  if (command_line.HasSwitch(switches::kEnablePushMessagePayload))
-    WebRuntimeFeatures::enablePushMessagingData(true);
-
   if (command_line.HasSwitch(switches::kDisablePermissionsAPI))
     WebRuntimeFeatures::enablePermissionsAPI(false);
 
diff --git a/content/child/service_worker/service_worker_dispatcher.cc b/content/child/service_worker/service_worker_dispatcher.cc
index 5426087..832395a 100644
--- a/content/child/service_worker/service_worker_dispatcher.cc
+++ b/content/child/service_worker/service_worker_dispatcher.cc
@@ -300,7 +300,7 @@
   registration->SetActive(
       GetOrCreateServiceWorker(ServiceWorkerHandleReference::Create(
           attrs.active, thread_safe_sender_.get())));
-  return registration.Pass();
+  return registration;
 }
 
 scoped_refptr<WebServiceWorkerRegistrationImpl>
@@ -325,7 +325,7 @@
   registration->SetInstalling(GetOrCreateServiceWorker(installing_ref.Pass()));
   registration->SetWaiting(GetOrCreateServiceWorker(waiting_ref.Pass()));
   registration->SetActive(GetOrCreateServiceWorker(active_ref.Pass()));
-  return registration.Pass();
+  return registration;
 }
 
 void ServiceWorkerDispatcher::OnAssociateRegistration(
diff --git a/content/common/BUILD.gn b/content/common/BUILD.gn
index dc85add3..759bf97 100644
--- a/content/common/BUILD.gn
+++ b/content/common/BUILD.gn
@@ -231,9 +231,9 @@
                  "gpu/client/gpu_memory_buffer_impl_io_surface.h",
                  "gpu/gpu_memory_buffer_factory_io_surface.cc",
                  "gpu/gpu_memory_buffer_factory_io_surface.h",
-                 "gpu/media/vt.h",
-                 "gpu/media/vt_video_decode_accelerator.cc",
-                 "gpu/media/vt_video_decode_accelerator.h",
+                 "gpu/media/vt_mac.h",
+                 "gpu/media/vt_video_decode_accelerator_mac.cc",
+                 "gpu/media/vt_video_decode_accelerator_mac.h",
                ] + get_target_outputs(":libvt_generate_stubs")
 
     sources -= [ "plugin_list_posix.cc" ]
@@ -469,8 +469,8 @@
 
   if (is_win) {
     sources += [
-      "gpu/media/dxva_video_decode_accelerator.cc",
-      "gpu/media/dxva_video_decode_accelerator.h",
+      "gpu/media/dxva_video_decode_accelerator_win.cc",
+      "gpu/media/dxva_video_decode_accelerator_win.h",
     ]
     configs += [ "//third_party/khronos:khronos_headers" ]
     deps += [ "//ui/gl" ]
diff --git a/content/common/browser_plugin/browser_plugin_messages.h b/content/common/browser_plugin/browser_plugin_messages.h
index ca06826..91f5f60 100644
--- a/content/common/browser_plugin/browser_plugin_messages.h
+++ b/content/common/browser_plugin/browser_plugin_messages.h
@@ -37,7 +37,6 @@
 
 
 IPC_ENUM_TRAITS_MAX_VALUE(blink::WebDragStatus, blink::WebDragStatusLast)
-IPC_ENUM_TRAITS_MAX_VALUE(blink::WebFocusType, blink::WebFocusTypeLast)
 
 IPC_STRUCT_BEGIN(BrowserPluginHostMsg_Attach_Params)
   IPC_STRUCT_MEMBER(bool, focused)
diff --git a/content/common/cursors/webcursor.cc b/content/common/cursors/webcursor.cc
index faa6d703..b2dfcdf 100644
--- a/content/common/cursors/webcursor.cc
+++ b/content/common/cursors/webcursor.cc
@@ -112,8 +112,12 @@
     if (size_x > 0 && size_y > 0) {
       // The * 4 is because the expected format is an array of RGBA pixel
       // values.
-      if (size_x * size_y * 4 > data_len)
+      if (size_x * size_y * 4 != data_len) {
+        LOG(WARNING) << "WebCursor's data length and image size mismatch: "
+                     << size_x << "x" << size_y << "x4 != "
+                     << data_len;
         return false;
+      }
 
       hotspot_.set_x(hotspot_x);
       hotspot_.set_y(hotspot_y);
diff --git a/content/common/frame_messages.h b/content/common/frame_messages.h
index f4fc8b5..01d5fdf 100644
--- a/content/common/frame_messages.h
+++ b/content/common/frame_messages.h
@@ -29,6 +29,7 @@
 #include "content/public/common/three_d_api_types.h"
 #include "content/public/common/transition_element.h"
 #include "ipc/ipc_message_macros.h"
+#include "third_party/WebKit/public/platform/WebFocusType.h"
 #include "third_party/WebKit/public/web/WebFrameOwnerProperties.h"
 #include "third_party/WebKit/public/web/WebTreeScopeType.h"
 #include "ui/gfx/ipc/gfx_param_traits.h"
@@ -58,6 +59,7 @@
                           blink::WebContextMenuData::MediaTypeLast)
 IPC_ENUM_TRAITS_MAX_VALUE(blink::WebContextMenuData::InputFieldType,
                           blink::WebContextMenuData::InputFieldTypeLast)
+IPC_ENUM_TRAITS_MAX_VALUE(blink::WebFocusType, blink::WebFocusTypeLast)
 IPC_ENUM_TRAITS_MAX_VALUE(blink::WebFrameOwnerProperties::ScrollingMode,
                           blink::WebFrameOwnerProperties::ScrollingMode::Last)
 IPC_ENUM_TRAITS(blink::WebSandboxFlags)  // Bitmask.
@@ -720,6 +722,14 @@
 IPC_MESSAGE_ROUTED1(FrameMsg_SetFrameOwnerProperties,
                     blink::WebFrameOwnerProperties /* frame_owner_properties */)
 
+// Request to continue running the sequential focus navigation algorithm in
+// this frame.  |source_routing_id| identifies the frame that issued this
+// request.  This message is sent when pressing <tab> or <shift-tab> needs to
+// find the next focusable element in a cross-process frame.
+IPC_MESSAGE_ROUTED2(FrameMsg_AdvanceFocus,
+                    blink::WebFocusType /* type */,
+                    int32_t /* source_routing_id */)
+
 #if defined(ENABLE_PLUGINS)
 // Notifies the renderer of updates to the Plugin Power Saver origin whitelist.
 IPC_MESSAGE_ROUTED1(FrameMsg_UpdatePluginContentOriginWhitelist,
@@ -1250,6 +1260,15 @@
 IPC_MESSAGE_ROUTED1(FrameHostMsg_UpdatePageImportanceSignals,
                     content::PageImportanceSignals)
 
+// This message is sent from a RenderFrameProxy when sequential focus
+// navigation needs to advance into its actual frame.  |source_routing_id|
+// identifies the frame that issued this request.  This is used when pressing
+// <tab> or <shift-tab> hits an out-of-process iframe when searching for the
+// next focusable element.
+IPC_MESSAGE_ROUTED2(FrameHostMsg_AdvanceFocus,
+                    blink::WebFocusType /* type */,
+                    int32_t /* source_routing_id */)
+
 #if defined(OS_MACOSX) || defined(OS_ANDROID)
 
 // Message to show/hide a popup menu using native controls.
diff --git a/content/common/gpu/client/gpu_video_decode_accelerator_host.cc b/content/common/gpu/client/gpu_video_decode_accelerator_host.cc
index a329dcc..621d210 100644
--- a/content/common/gpu/client/gpu_video_decode_accelerator_host.cc
+++ b/content/common/gpu/client/gpu_video_decode_accelerator_host.cc
@@ -81,7 +81,7 @@
   PostNotifyError(PLATFORM_FAILURE);
 }
 
-bool GpuVideoDecodeAcceleratorHost::Initialize(media::VideoCodecProfile profile,
+bool GpuVideoDecodeAcceleratorHost::Initialize(const Config& config,
                                                Client* client) {
   DCHECK(CalledOnValidThread());
   client_ = client;
@@ -93,7 +93,7 @@
   channel_->AddRoute(route_id, weak_this_factory_.GetWeakPtr());
 
   bool succeeded = false;
-  Send(new GpuCommandBufferMsg_CreateVideoDecoder(impl_->route_id(), profile,
+  Send(new GpuCommandBufferMsg_CreateVideoDecoder(impl_->route_id(), config,
                                                   route_id, &succeeded));
 
   if (!succeeded) {
diff --git a/content/common/gpu/client/gpu_video_decode_accelerator_host.h b/content/common/gpu/client/gpu_video_decode_accelerator_host.h
index 9f9e8e2..33a516f 100644
--- a/content/common/gpu/client/gpu_video_decode_accelerator_host.h
+++ b/content/common/gpu/client/gpu_video_decode_accelerator_host.h
@@ -35,7 +35,7 @@
   bool OnMessageReceived(const IPC::Message& message) override;
 
   // media::VideoDecodeAccelerator implementation.
-  bool Initialize(media::VideoCodecProfile profile, Client* client) override;
+  bool Initialize(const Config& config, Client* client) override;
   void SetCdm(int cdm_id) override;
   void Decode(const media::BitstreamBuffer& bitstream_buffer) override;
   void AssignPictureBuffers(
diff --git a/content/common/gpu/gpu_command_buffer_stub.cc b/content/common/gpu/gpu_command_buffer_stub.cc
index eead7fb3..86a3711 100644
--- a/content/common/gpu/gpu_command_buffer_stub.cc
+++ b/content/common/gpu/gpu_command_buffer_stub.cc
@@ -881,13 +881,13 @@
 }
 
 void GpuCommandBufferStub::OnCreateVideoDecoder(
-    media::VideoCodecProfile profile,
+    const media::VideoDecodeAccelerator::Config& config,
     int32 decoder_route_id,
     IPC::Message* reply_message) {
   TRACE_EVENT0("gpu", "GpuCommandBufferStub::OnCreateVideoDecoder");
   GpuVideoDecodeAccelerator* decoder = new GpuVideoDecodeAccelerator(
       decoder_route_id, this, channel_->io_task_runner());
-  decoder->Initialize(profile, reply_message);
+  decoder->Initialize(config, reply_message);
   // decoder is registered as a DestructionObserver of this stub and will
   // self-delete during destruction of this stub.
 }
diff --git a/content/common/gpu/gpu_command_buffer_stub.h b/content/common/gpu/gpu_command_buffer_stub.h
index 2e529a6..188ede0 100644
--- a/content/common/gpu/gpu_command_buffer_stub.h
+++ b/content/common/gpu/gpu_command_buffer_stub.h
@@ -21,7 +21,7 @@
 #include "gpu/command_buffer/service/gpu_scheduler.h"
 #include "ipc/ipc_listener.h"
 #include "ipc/ipc_sender.h"
-#include "media/base/video_decoder_config.h"
+#include "media/video/video_decode_accelerator.h"
 #include "ui/events/latency_info.h"
 #include "ui/gfx/geometry/size.h"
 #include "ui/gfx/gpu_memory_buffer.h"
@@ -180,7 +180,7 @@
   void OnDestroyTransferBuffer(int32 id);
   void OnGetTransferBuffer(int32 id, IPC::Message* reply_message);
 
-  void OnCreateVideoDecoder(media::VideoCodecProfile profile,
+  void OnCreateVideoDecoder(const media::VideoDecodeAccelerator::Config& config,
                             int32 route_id,
                             IPC::Message* reply_message);
   void OnCreateVideoEncoder(media::VideoPixelFormat input_format,
diff --git a/content/common/gpu/gpu_messages.h b/content/common/gpu/gpu_messages.h
index e75ed254..d463ef0f 100644
--- a/content/common/gpu/gpu_messages.h
+++ b/content/common/gpu/gpu_messages.h
@@ -216,6 +216,11 @@
   IPC_STRUCT_TRAITS_MEMBER(device_string)
 IPC_STRUCT_TRAITS_END()
 
+IPC_STRUCT_TRAITS_BEGIN(media::VideoDecodeAccelerator::Config)
+  IPC_STRUCT_TRAITS_MEMBER(profile)
+  IPC_STRUCT_TRAITS_MEMBER(is_encrypted)
+IPC_STRUCT_TRAITS_END()
+
 IPC_STRUCT_TRAITS_BEGIN(gpu::VideoDecodeAcceleratorSupportedProfile)
   IPC_STRUCT_TRAITS_MEMBER(profile)
   IPC_STRUCT_TRAITS_MEMBER(max_resolution)
@@ -600,7 +605,7 @@
 // Created decoders should be freed with AcceleratedVideoDecoderMsg_Destroy when
 // no longer needed.
 IPC_SYNC_MESSAGE_ROUTED2_1(GpuCommandBufferMsg_CreateVideoDecoder,
-                           media::VideoCodecProfile /* profile */,
+                           media::VideoDecodeAccelerator::Config, /* config */
                            int32, /* route_id */
                            bool /* succeeded */)
 
diff --git a/content/common/gpu/media/android_video_decode_accelerator.cc b/content/common/gpu/media/android_video_decode_accelerator.cc
index 3f1e8774..00e1bb6 100644
--- a/content/common/gpu/media/android_video_decode_accelerator.cc
+++ b/content/common/gpu/media/android_video_decode_accelerator.cc
@@ -81,6 +81,7 @@
     : client_(NULL),
       make_context_current_(make_context_current),
       codec_(media::kCodecH264),
+      is_encrypted_(false),
       state_(NO_ERROR),
       picturebuffers_requested_(false),
       gl_decoder_(decoder),
@@ -91,14 +92,18 @@
   DCHECK(thread_checker_.CalledOnValidThread());
 }
 
-bool AndroidVideoDecodeAccelerator::Initialize(media::VideoCodecProfile profile,
+bool AndroidVideoDecodeAccelerator::Initialize(const Config& config,
                                                Client* client) {
   DCHECK(!media_codec_);
   DCHECK(thread_checker_.CalledOnValidThread());
   TRACE_EVENT0("media", "AVDA::Initialize");
 
+  DVLOG(1) << __FUNCTION__ << ": profile:" << config.profile
+           << " is_encrypted:" << config.is_encrypted;
+
   client_ = client;
-  codec_ = VideoCodecProfileToVideoCodec(profile);
+  codec_ = VideoCodecProfileToVideoCodec(config.profile);
+  is_encrypted_ = config.is_encrypted;
 
   bool profile_supported = codec_ == media::kCodecVP8;
 #if defined(ENABLE_MEDIA_PIPELINE_ON_ANDROID)
@@ -107,7 +112,7 @@
 #endif
 
   if (!profile_supported) {
-    LOG(ERROR) << "Unsupported profile: " << profile;
+    LOG(ERROR) << "Unsupported profile: " << config.profile;
     return false;
   }
 
diff --git a/content/common/gpu/media/android_video_decode_accelerator.h b/content/common/gpu/media/android_video_decode_accelerator.h
index 8384bc8..2e8058af 100644
--- a/content/common/gpu/media/android_video_decode_accelerator.h
+++ b/content/common/gpu/media/android_video_decode_accelerator.h
@@ -95,7 +95,7 @@
   ~AndroidVideoDecodeAccelerator() override;
 
   // media::VideoDecodeAccelerator implementation:
-  bool Initialize(media::VideoCodecProfile profile, Client* client) override;
+  bool Initialize(const Config& config, Client* client) override;
   void SetCdm(int cdm_id) override;
   void Decode(const media::BitstreamBuffer& bitstream_buffer) override;
   void AssignPictureBuffers(
@@ -178,6 +178,9 @@
   // Codec type. Used when we configure media codec.
   media::VideoCodec codec_;
 
+  // Whether the stream is encrypted.
+  bool is_encrypted_;
+
   // The current state of this class. For now, this is used only for setting
   // error state.
   State state_;
diff --git a/content/common/gpu/media/dxva_video_decode_accelerator.cc b/content/common/gpu/media/dxva_video_decode_accelerator_win.cc
similarity index 99%
rename from content/common/gpu/media/dxva_video_decode_accelerator.cc
rename to content/common/gpu/media/dxva_video_decode_accelerator_win.cc
index 46e9dce..0e71f1e 100644
--- a/content/common/gpu/media/dxva_video_decode_accelerator.cc
+++ b/content/common/gpu/media/dxva_video_decode_accelerator_win.cc
@@ -2,15 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/common/gpu/media/dxva_video_decode_accelerator.h"
+#include "content/common/gpu/media/dxva_video_decode_accelerator_win.h"
 
 #if !defined(OS_WIN)
 #error This file should only be built on Windows.
 #endif   // !defined(OS_WIN)
 
-#include <ks.h>
 #include <codecapi.h>
 #include <dxgi1_2.h>
+#include <ks.h>
 #include <mfapi.h>
 #include <mferror.h>
 #include <ntverp.h>
@@ -632,15 +632,20 @@
   client_ = NULL;
 }
 
-bool DXVAVideoDecodeAccelerator::Initialize(media::VideoCodecProfile profile,
-                                           Client* client) {
+bool DXVAVideoDecodeAccelerator::Initialize(const Config& config,
+                                            Client* client) {
+  if (config.is_encrypted) {
+    NOTREACHED() << "Encrypted streams are not supported for this VDA";
+    return false;
+  }
+
   client_ = client;
 
   main_thread_task_runner_ = base::MessageLoop::current()->task_runner();
 
   bool profile_supported = false;
   for (const auto& supported_profile : kSupportedProfiles) {
-    if (profile == supported_profile) {
+    if (config.profile == supported_profile) {
       profile_supported = true;
       break;
     }
@@ -692,7 +697,7 @@
 
   media::InitializeMediaFoundation();
 
-  RETURN_AND_NOTIFY_ON_FAILURE(InitDecoder(profile),
+  RETURN_AND_NOTIFY_ON_FAILURE(InitDecoder(config.profile),
       "Failed to initialize decoder", PLATFORM_FAILURE, false);
 
   RETURN_AND_NOTIFY_ON_FAILURE(GetStreamsInfoAndBufferReqs(),
diff --git a/content/common/gpu/media/dxva_video_decode_accelerator.h b/content/common/gpu/media/dxva_video_decode_accelerator_win.h
similarity index 98%
rename from content/common/gpu/media/dxva_video_decode_accelerator.h
rename to content/common/gpu/media/dxva_video_decode_accelerator_win.h
index 86125ed..d3e85fe 100644
--- a/content/common/gpu/media/dxva_video_decode_accelerator.h
+++ b/content/common/gpu/media/dxva_video_decode_accelerator_win.h
@@ -64,8 +64,7 @@
   ~DXVAVideoDecodeAccelerator() override;
 
   // media::VideoDecodeAccelerator implementation.
-  bool Initialize(media::VideoCodecProfile profile,
-                  Client* client) override;
+  bool Initialize(const Config& config, Client* client) override;
   void Decode(const media::BitstreamBuffer& bitstream_buffer) override;
   void AssignPictureBuffers(
       const std::vector<media::PictureBuffer>& buffers) override;
diff --git a/content/common/gpu/media/fake_video_decode_accelerator.cc b/content/common/gpu/media/fake_video_decode_accelerator.cc
index eff497f4..12aec65 100644
--- a/content/common/gpu/media/fake_video_decode_accelerator.cc
+++ b/content/common/gpu/media/fake_video_decode_accelerator.cc
@@ -41,13 +41,18 @@
 FakeVideoDecodeAccelerator::~FakeVideoDecodeAccelerator() {
 }
 
-bool FakeVideoDecodeAccelerator::Initialize(media::VideoCodecProfile profile,
+bool FakeVideoDecodeAccelerator::Initialize(const Config& config,
                                             Client* client) {
   DCHECK(child_task_runner_->BelongsToCurrentThread());
-  if (profile == media::VIDEO_CODEC_PROFILE_UNKNOWN) {
+  if (config.profile == media::VIDEO_CODEC_PROFILE_UNKNOWN) {
     LOG(ERROR) << "unknown codec profile";
     return false;
   }
+  if (config.is_encrypted) {
+    NOTREACHED() << "encrypted streams are not supported";
+    return false;
+  }
+
   // V4L2VideoDecodeAccelerator waits until first decode call to ask for buffers
   // This class asks for it on initialization instead.
   client_ = client;
diff --git a/content/common/gpu/media/fake_video_decode_accelerator.h b/content/common/gpu/media/fake_video_decode_accelerator.h
index a669c823..bb88ff7 100644
--- a/content/common/gpu/media/fake_video_decode_accelerator.h
+++ b/content/common/gpu/media/fake_video_decode_accelerator.h
@@ -25,8 +25,7 @@
       const base::Callback<bool(void)>& make_context_current);
   ~FakeVideoDecodeAccelerator() override;
 
-  bool Initialize(media::VideoCodecProfile profile,
-                  Client* client) override;
+  bool Initialize(const Config& config, Client* client) override;
   void Decode(const media::BitstreamBuffer& bitstream_buffer) override;
   void AssignPictureBuffers(
       const std::vector<media::PictureBuffer>& buffers) override;
diff --git a/content/common/gpu/media/gpu_video_decode_accelerator.cc b/content/common/gpu/media/gpu_video_decode_accelerator.cc
index ed4d179..2dfe85b 100644
--- a/content/common/gpu/media/gpu_video_decode_accelerator.cc
+++ b/content/common/gpu/media/gpu_video_decode_accelerator.cc
@@ -30,9 +30,9 @@
 
 #if defined(OS_WIN)
 #include "base/win/windows_version.h"
-#include "content/common/gpu/media/dxva_video_decode_accelerator.h"
+#include "content/common/gpu/media/dxva_video_decode_accelerator_win.h"
 #elif defined(OS_MACOSX)
-#include "content/common/gpu/media/vt_video_decode_accelerator.h"
+#include "content/common/gpu/media/vt_video_decode_accelerator_mac.h"
 #elif defined(OS_CHROMEOS)
 #if defined(USE_V4L2_CODEC)
 #include "content/common/gpu/media/v4l2_device.h"
@@ -323,7 +323,7 @@
 }
 
 void GpuVideoDecodeAccelerator::Initialize(
-    const media::VideoCodecProfile profile,
+    const media::VideoDecodeAccelerator::Config& config,
     IPC::Message* init_done_msg) {
   DCHECK(!video_decode_accelerator_);
 
@@ -356,7 +356,7 @@
   for (const auto& create_vda_function : create_vda_fps) {
     video_decode_accelerator_ = (this->*create_vda_function)();
     if (!video_decode_accelerator_ ||
-        !video_decode_accelerator_->Initialize(profile, this))
+        !video_decode_accelerator_->Initialize(config, this))
       continue;
 
     if (video_decode_accelerator_->CanDecodeOnIOThread()) {
@@ -367,7 +367,8 @@
     return;
   }
   video_decode_accelerator_.reset();
-  LOG(ERROR) << "HW video decode not available for profile " << profile;
+  LOG(ERROR) << "HW video decode not available for profile " << config.profile
+             << (config.is_encrypted ? " with encryption" : "");
   SendCreateDecoderReply(init_done_msg, false);
 }
 
diff --git a/content/common/gpu/media/gpu_video_decode_accelerator.h b/content/common/gpu/media/gpu_video_decode_accelerator.h
index ad1e142f..b6fba877 100644
--- a/content/common/gpu/media/gpu_video_decode_accelerator.h
+++ b/content/common/gpu/media/gpu_video_decode_accelerator.h
@@ -65,10 +65,10 @@
   bool Send(IPC::Message* message) override;
 
   // Initialize VDAs from the set of VDAs supported for current platform until
-  // one of them succeeds for given |profile|. Send the |init_done_msg| when
+  // one of them succeeds for given |config|. Send the |init_done_msg| when
   // done. filter_ is passed to GpuCommandBufferStub channel only if the chosen
   // VDA can decode on IO thread.
-  void Initialize(const media::VideoCodecProfile profile,
+  void Initialize(const media::VideoDecodeAccelerator::Config& config,
                   IPC::Message* init_done_msg);
 
  private:
diff --git a/content/common/gpu/media/v4l2_slice_video_decode_accelerator.cc b/content/common/gpu/media/v4l2_slice_video_decode_accelerator.cc
index a682648b..f17dc629 100644
--- a/content/common/gpu/media/v4l2_slice_video_decode_accelerator.cc
+++ b/content/common/gpu/media/v4l2_slice_video_decode_accelerator.cc
@@ -433,10 +433,14 @@
   }
 }
 
-bool V4L2SliceVideoDecodeAccelerator::Initialize(
-    media::VideoCodecProfile profile,
-    VideoDecodeAccelerator::Client* client) {
-  DVLOGF(3) << "profile: " << profile;
+bool V4L2SliceVideoDecodeAccelerator::Initialize(const Config& config,
+                                                 Client* client) {
+  DVLOGF(3) << "profile: " << config.profile;
+  if (config.is_encrypted) {
+    NOTREACHED() << "Encrypted streams are not supported for this VDA";
+    return false;
+  }
+
   DCHECK(child_task_runner_->BelongsToCurrentThread());
   DCHECK_EQ(state_, kUninitialized);
 
@@ -444,7 +448,7 @@
       new base::WeakPtrFactory<VideoDecodeAccelerator::Client>(client));
   client_ = client_ptr_factory_->GetWeakPtr();
 
-  video_profile_ = profile;
+  video_profile_ = config.profile;
 
   if (video_profile_ >= media::H264PROFILE_MIN &&
       video_profile_ <= media::H264PROFILE_MAX) {
diff --git a/content/common/gpu/media/v4l2_slice_video_decode_accelerator.h b/content/common/gpu/media/v4l2_slice_video_decode_accelerator.h
index dd12487..4a7c9075 100644
--- a/content/common/gpu/media/v4l2_slice_video_decode_accelerator.h
+++ b/content/common/gpu/media/v4l2_slice_video_decode_accelerator.h
@@ -42,8 +42,7 @@
   ~V4L2SliceVideoDecodeAccelerator() override;
 
   // media::VideoDecodeAccelerator implementation.
-  bool Initialize(media::VideoCodecProfile profile,
-                  VideoDecodeAccelerator::Client* client) override;
+  bool Initialize(const Config& config, Client* client) override;
   void Decode(const media::BitstreamBuffer& bitstream_buffer) override;
   void AssignPictureBuffers(
       const std::vector<media::PictureBuffer>& buffers) override;
diff --git a/content/common/gpu/media/v4l2_video_decode_accelerator.cc b/content/common/gpu/media/v4l2_video_decode_accelerator.cc
index f217080..64672fc 100644
--- a/content/common/gpu/media/v4l2_video_decode_accelerator.cc
+++ b/content/common/gpu/media/v4l2_video_decode_accelerator.cc
@@ -199,16 +199,21 @@
   DCHECK(output_buffer_map_.empty());
 }
 
-bool V4L2VideoDecodeAccelerator::Initialize(media::VideoCodecProfile profile,
+bool V4L2VideoDecodeAccelerator::Initialize(const Config& config,
                                             Client* client) {
   DVLOG(3) << "Initialize()";
+  if (config.is_encrypted) {
+    NOTREACHED() << "Encrypted streams are not supported for this VDA";
+    return false;
+  }
+
   DCHECK(child_task_runner_->BelongsToCurrentThread());
   DCHECK_EQ(decoder_state_, kUninitialized);
 
   client_ptr_factory_.reset(new base::WeakPtrFactory<Client>(client));
   client_ = client_ptr_factory_->GetWeakPtr();
 
-  switch (profile) {
+  switch (config.profile) {
     case media::H264PROFILE_BASELINE:
       DVLOG(2) << "Initialize(): profile H264PROFILE_BASELINE";
       break;
@@ -225,10 +230,10 @@
       DVLOG(2) << "Initialize(): profile VP9PROFILE_ANY";
       break;
     default:
-      DLOG(ERROR) << "Initialize(): unsupported profile=" << profile;
+      DLOG(ERROR) << "Initialize(): unsupported profile=" << config.profile;
       return false;
   };
-  video_profile_ = profile;
+  video_profile_ = config.profile;
 
   if (egl_display_ == EGL_NO_DISPLAY) {
     LOG(ERROR) << "Initialize(): could not get EGLDisplay";
diff --git a/content/common/gpu/media/v4l2_video_decode_accelerator.h b/content/common/gpu/media/v4l2_video_decode_accelerator.h
index 58daa0eb8..58fc6f4 100644
--- a/content/common/gpu/media/v4l2_video_decode_accelerator.h
+++ b/content/common/gpu/media/v4l2_video_decode_accelerator.h
@@ -83,8 +83,7 @@
 
   // media::VideoDecodeAccelerator implementation.
   // Note: Initialize() and Destroy() are synchronous.
-  bool Initialize(media::VideoCodecProfile profile,
-                  Client* client) override;
+  bool Initialize(const Config& config, Client* client) override;
   void Decode(const media::BitstreamBuffer& bitstream_buffer) override;
   void AssignPictureBuffers(
       const std::vector<media::PictureBuffer>& buffers) override;
diff --git a/content/common/gpu/media/vaapi_video_decode_accelerator.cc b/content/common/gpu/media/vaapi_video_decode_accelerator.cc
index bce58ab6..fab601ed 100644
--- a/content/common/gpu/media/vaapi_video_decode_accelerator.cc
+++ b/content/common/gpu/media/vaapi_video_decode_accelerator.cc
@@ -316,13 +316,20 @@
   DCHECK_EQ(message_loop_, base::MessageLoop::current());
 }
 
-bool VaapiVideoDecodeAccelerator::Initialize(media::VideoCodecProfile profile,
+bool VaapiVideoDecodeAccelerator::Initialize(const Config& config,
                                              Client* client) {
   DCHECK_EQ(message_loop_, base::MessageLoop::current());
 
+  if (config.is_encrypted) {
+    NOTREACHED() << "Encrypted streams are not supported for this VDA";
+    return false;
+  }
+
   client_ptr_factory_.reset(new base::WeakPtrFactory<Client>(client));
   client_ = client_ptr_factory_->GetWeakPtr();
 
+  media::VideoCodecProfile profile = config.profile;
+
   base::AutoLock auto_lock(lock_);
   DCHECK_EQ(state_, kUninitialized);
   DVLOG(2) << "Initializing VAVDA, profile: " << profile;
diff --git a/content/common/gpu/media/vaapi_video_decode_accelerator.h b/content/common/gpu/media/vaapi_video_decode_accelerator.h
index e870351..1244893 100644
--- a/content/common/gpu/media/vaapi_video_decode_accelerator.h
+++ b/content/common/gpu/media/vaapi_video_decode_accelerator.h
@@ -57,7 +57,7 @@
   ~VaapiVideoDecodeAccelerator() override;
 
   // media::VideoDecodeAccelerator implementation.
-  bool Initialize(media::VideoCodecProfile profile, Client* client) override;
+  bool Initialize(const Config& config, Client* client) override;
   void Decode(const media::BitstreamBuffer& bitstream_buffer) override;
   void AssignPictureBuffers(
       const std::vector<media::PictureBuffer>& buffers) override;
diff --git a/content/common/gpu/media/video_decode_accelerator_unittest.cc b/content/common/gpu/media/video_decode_accelerator_unittest.cc
index 9a8b774..82c5b692 100644
--- a/content/common/gpu/media/video_decode_accelerator_unittest.cc
+++ b/content/common/gpu/media/video_decode_accelerator_unittest.cc
@@ -57,7 +57,7 @@
 
 #if defined(OS_WIN)
 #include "base/win/windows_version.h"
-#include "content/common/gpu/media/dxva_video_decode_accelerator.h"
+#include "content/common/gpu/media/dxva_video_decode_accelerator_win.h"
 #elif defined(OS_CHROMEOS)
 #if defined(USE_V4L2_CODEC)
 #include "content/common/gpu/media/v4l2_device.h"
diff --git a/content/common/gpu/media/vt.h b/content/common/gpu/media/vt_mac.h
similarity index 100%
rename from content/common/gpu/media/vt.h
rename to content/common/gpu/media/vt_mac.h
diff --git a/content/common/gpu/media/vt_video_decode_accelerator.cc b/content/common/gpu/media/vt_video_decode_accelerator_mac.cc
similarity index 98%
rename from content/common/gpu/media/vt_video_decode_accelerator.cc
rename to content/common/gpu/media/vt_video_decode_accelerator_mac.cc
index a98ce79c..6b3e0dc7 100644
--- a/content/common/gpu/media/vt_video_decode_accelerator.cc
+++ b/content/common/gpu/media/vt_video_decode_accelerator_mac.cc
@@ -17,7 +17,7 @@
 #include "base/sys_info.h"
 #include "base/thread_task_runner_handle.h"
 #include "base/version.h"
-#include "content/common/gpu/media/vt_video_decode_accelerator.h"
+#include "content/common/gpu/media/vt_video_decode_accelerator_mac.h"
 #include "content/public/common/content_switches.h"
 #include "media/base/limits.h"
 #include "ui/gl/gl_context.h"
@@ -313,10 +313,15 @@
   DCHECK(gpu_thread_checker_.CalledOnValidThread());
 }
 
-bool VTVideoDecodeAccelerator::Initialize(
-    media::VideoCodecProfile profile,
-    Client* client) {
+bool VTVideoDecodeAccelerator::Initialize(const Config& config,
+                                          Client* client) {
   DCHECK(gpu_thread_checker_.CalledOnValidThread());
+
+  if (config.is_encrypted) {
+    NOTREACHED() << "Encrypted streams are not supported for this VDA";
+    return false;
+  }
+
   client_ = client;
 
   if (!InitializeVideoToolbox())
@@ -324,7 +329,7 @@
 
   bool profile_supported = false;
   for (const auto& supported_profile : kSupportedProfiles) {
-    if (profile == supported_profile) {
+    if (config.profile == supported_profile) {
       profile_supported = true;
       break;
     }
diff --git a/content/common/gpu/media/vt_video_decode_accelerator.h b/content/common/gpu/media/vt_video_decode_accelerator_mac.h
similarity index 97%
rename from content/common/gpu/media/vt_video_decode_accelerator.h
rename to content/common/gpu/media/vt_video_decode_accelerator_mac.h
index 27f1c4e..27a8190 100644
--- a/content/common/gpu/media/vt_video_decode_accelerator.h
+++ b/content/common/gpu/media/vt_video_decode_accelerator_mac.h
@@ -11,12 +11,13 @@
 #include <queue>
 
 #include "base/mac/scoped_cftyperef.h"
+#include "base/macros.h"
 #include "base/memory/linked_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/message_loop/message_loop.h"
 #include "base/threading/thread.h"
 #include "base/threading/thread_checker.h"
-#include "content/common/gpu/media/vt.h"
+#include "content/common/gpu/media/vt_mac.h"
 #include "media/filters/h264_parser.h"
 #include "media/video/h264_poc.h"
 #include "media/video/video_decode_accelerator.h"
@@ -40,7 +41,7 @@
   ~VTVideoDecodeAccelerator() override;
 
   // VideoDecodeAccelerator implementation.
-  bool Initialize(media::VideoCodecProfile profile, Client* client) override;
+  bool Initialize(const Config& config, Client* client) override;
   void Decode(const media::BitstreamBuffer& bitstream) override;
   void AssignPictureBuffers(
       const std::vector<media::PictureBuffer>& pictures) override;
diff --git a/content/common/sandbox_linux/sandbox_seccomp_bpf_linux.cc b/content/common/sandbox_linux/sandbox_seccomp_bpf_linux.cc
index de2bcc0..0b8db74be 100644
--- a/content/common/sandbox_linux/sandbox_seccomp_bpf_linux.cc
+++ b/content/common/sandbox_linux/sandbox_seccomp_bpf_linux.cc
@@ -76,22 +76,6 @@
 
 #if !defined(OS_NACL_NONSFI)
 
-inline bool IsChromeOS() {
-#if defined(OS_CHROMEOS)
-  return true;
-#else
-  return false;
-#endif
-}
-
-inline bool IsArchitectureArm() {
-#if defined(__arm__)
-  return true;
-#else
-  return false;
-#endif
-}
-
 class BlacklistDebugAndNumaPolicy : public SandboxBPFBasePolicy {
  public:
   BlacklistDebugAndNumaPolicy() {}
@@ -128,6 +112,25 @@
   return Allow();
 }
 
+// nacl_helper needs to be tiny and includes only part of content/
+// in its dependencies. Make sure to not link things that are not needed.
+#if !defined(IN_NACL_HELPER)
+inline bool IsChromeOS() {
+#if defined(OS_CHROMEOS)
+  return true;
+#else
+  return false;
+#endif
+}
+
+inline bool IsArchitectureArm() {
+#if defined(__arm__)
+  return true;
+#else
+  return false;
+#endif
+}
+
 // If a BPF policy is engaged for |process_type|, run a few sanity checks.
 void RunSandboxSanityChecks(const std::string& process_type) {
   if (process_type == switches::kRendererProcess ||
@@ -157,9 +160,6 @@
   }
 }
 
-// nacl_helper needs to be tiny and includes only part of content/
-// in its dependencies. Make sure to not link things that are not needed.
-#if !defined(IN_NACL_HELPER)
 scoped_ptr<SandboxBPFBasePolicy> GetGpuProcessSandbox() {
   const base::CommandLine& command_line =
       *base::CommandLine::ForCurrentProcess();
@@ -210,10 +210,6 @@
 bool StartBPFSandbox(const base::CommandLine& command_line,
                      const std::string& process_type) {
   NOTREACHED();
-  // Avoid -Wunused-function with no-op code.
-  ignore_result(IsChromeOS);
-  ignore_result(IsArchitectureArm);
-  ignore_result(RunSandboxSanityChecks);
   return false;
 }
 #endif  // !defined(IN_NACL_HELPER)
diff --git a/content/common/sandbox_mac.mm b/content/common/sandbox_mac.mm
index 4dc7d94..8d28ffb0 100644
--- a/content/common/sandbox_mac.mm
+++ b/content/common/sandbox_mac.mm
@@ -33,7 +33,7 @@
 #include "base/strings/sys_string_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/sys_info.h"
-#include "content/common/gpu/media/vt_video_decode_accelerator.h"
+#include "content/common/gpu/media/vt_video_decode_accelerator_mac.h"
 #include "content/grit/content_resources.h"
 #include "content/public/common/content_client.h"
 #include "content/public/common/content_switches.h"
diff --git a/content/content_child.gypi b/content/content_child.gypi
index f74ecae..792e2fe03 100644
--- a/content/content_child.gypi
+++ b/content/content_child.gypi
@@ -153,16 +153,6 @@
       'child/npapi/plugin_instance_mac.mm',
       'child/npapi/plugin_lib.cc',
       'child/npapi/plugin_lib.h',
-      'child/npapi/plugin_stream.cc',
-      'child/npapi/plugin_stream.h',
-      'child/npapi/plugin_stream_posix.cc',
-      'child/npapi/plugin_stream_url.cc',
-      'child/npapi/plugin_stream_url.h',
-      'child/npapi/plugin_stream_win.cc',
-      'child/npapi/plugin_string_stream.cc',
-      'child/npapi/plugin_string_stream.h',
-      'child/npapi/plugin_url_fetcher.cc',
-      'child/npapi/plugin_url_fetcher.h',
       'child/npapi/plugin_web_event_converter_mac.h',
       'child/npapi/plugin_web_event_converter_mac.mm',
       'child/npapi/webplugin.h',
diff --git a/content/content_common.gypi b/content/content_common.gypi
index 8af6123..b809c351 100644
--- a/content/content_common.gypi
+++ b/content/content_common.gypi
@@ -676,9 +676,9 @@
         'common/gpu/client/gpu_memory_buffer_impl_io_surface.h',
         'common/gpu/gpu_memory_buffer_factory_io_surface.cc',
         'common/gpu/gpu_memory_buffer_factory_io_surface.h',
-        'common/gpu/media/vt.h',
-        'common/gpu/media/vt_video_decode_accelerator.cc',
-        'common/gpu/media/vt_video_decode_accelerator.h',
+        'common/gpu/media/vt_mac.h',
+        'common/gpu/media/vt_video_decode_accelerator_mac.cc',
+        'common/gpu/media/vt_video_decode_accelerator_mac.h',
       ],
       'sources!': [
         'common/plugin_list_posix.cc',
@@ -1039,8 +1039,8 @@
         },
       },
       'sources': [
-        'common/gpu/media/dxva_video_decode_accelerator.cc',
-        'common/gpu/media/dxva_video_decode_accelerator.h',
+        'common/gpu/media/dxva_video_decode_accelerator_win.cc',
+        'common/gpu/media/dxva_video_decode_accelerator_win.h',
       ],
       'include_dirs': [
         '<(DEPTH)/third_party/khronos',
diff --git a/content/content_shell.gypi b/content/content_shell.gypi
index 9462cc4d..5b81135 100644
--- a/content/content_shell.gypi
+++ b/content/content_shell.gypi
@@ -573,12 +573,8 @@
         'shell/tools/plugin/PluginTest.cpp',
         'shell/tools/plugin/PluginTest.h',
         'shell/tools/plugin/TestObject.cpp',
-        'shell/tools/plugin/Tests/DocumentOpenInDestroyStream.cpp',
         'shell/tools/plugin/Tests/EvaluateJSAfterRemovingPluginElement.cpp',
         'shell/tools/plugin/Tests/FormValue.cpp',
-        'shell/tools/plugin/Tests/GetURLNotifyWithURLThatFailsToLoad.cpp',
-        'shell/tools/plugin/Tests/GetURLWithJavaScriptURL.cpp',
-        'shell/tools/plugin/Tests/GetURLWithJavaScriptURLDestroyingPlugin.cpp',
         'shell/tools/plugin/Tests/GetUserAgentWithNullNPPFromNPPNew.cpp',
         'shell/tools/plugin/Tests/LeakWindowScriptableObject.cpp',
         'shell/tools/plugin/Tests/LogNPPSetWindow.cpp',
diff --git a/content/content_tests.gypi b/content/content_tests.gypi
index 2e9ec20..5dfc0a5 100644
--- a/content/content_tests.gypi
+++ b/content/content_tests.gypi
@@ -75,6 +75,8 @@
       'public/test/test_browser_thread_bundle.h',
       'public/test/test_content_client_initializer.cc',
       'public/test/test_content_client_initializer.h',
+      'public/test/test_download_request_handler.cc',
+      'public/test/test_download_request_handler.h',
       'public/test/test_file_error_injector.cc',
       'public/test/test_file_error_injector.h',
       'public/test/test_file_system_backend.cc',
@@ -220,15 +222,16 @@
       'browser/frame_host/navigation_controller_impl_browsertest.cc',
       'browser/frame_host/render_frame_host_impl_browsertest.cc',
       'browser/frame_host/render_frame_host_manager_browsertest.cc',
+      'browser/frame_host/render_frame_message_filter_browsertest.cc',
       'browser/frame_host/render_widget_host_view_child_frame_browsertest.cc',
       'browser/gpu/gpu_ipc_browsertests.cc',
       'browser/host_zoom_map_impl_browsertest.cc',
       'browser/indexed_db/indexed_db_browsertest.cc',
       'browser/indexed_db/mock_browsertest_indexed_db_class_factory.cc',
       'browser/indexed_db/mock_browsertest_indexed_db_class_factory.h',
-      'browser/loader/resource_dispatcher_host_browsertest.cc',
-      'browser/loader/cross_site_resource_handler_browsertest.cc',
       'browser/loader/async_resource_handler_browsertest.cc',
+      'browser/loader/cross_site_resource_handler_browsertest.cc',
+      'browser/loader/resource_dispatcher_host_browsertest.cc',
       'browser/manifest/manifest_browsertest.cc',
       'browser/media/android/media_session_browsertest.cc',
       'browser/media/encrypted_media_browsertest.cc',
@@ -243,7 +246,6 @@
       'browser/renderer_host/input/touch_action_browsertest.cc',
       'browser/renderer_host/input/touch_input_browsertest.cc',
       'browser/renderer_host/input/touch_selection_controller_client_aura_browsertest.cc',
-      'browser/renderer_host/render_message_filter_browsertest.cc',
       'browser/renderer_host/render_process_host_browsertest.cc',
       'browser/renderer_host/render_view_host_browsertest.cc',
       'browser/renderer_host/render_widget_host_view_browsertest.cc',
@@ -498,9 +500,9 @@
       'browser/media/android/media_session_uma_helper_unittest.cc',
       'browser/media/audio_stream_monitor_unittest.cc',
       'browser/media/capture/audio_mirroring_manager_unittest.cc',
+      'browser/media/capture/cursor_renderer_aura_unittest.cc',
       'browser/media/capture/web_contents_audio_input_stream_unittest.cc',
       'browser/media/capture/web_contents_video_capture_device_unittest.cc',
-      'browser/media/capture/cursor_renderer_aura_unittest.cc',
       'browser/media/media_internals_unittest.cc',
       'browser/media/midi_host_unittest.cc',
       'browser/media/webrtc_identity_store_unittest.cc',
@@ -652,10 +654,10 @@
       'common/fileapi/file_system_util_unittest.cc',
       'common/font_warmup_win_unittest.cc',
       'common/gpu/client/gpu_memory_buffer_impl_shared_memory_unittest.cc',
+      'common/gpu/gpu_channel_manager_unittest.cc',
       'common/gpu/gpu_channel_test_common.cc',
       'common/gpu/gpu_channel_test_common.h',
       'common/gpu/gpu_channel_unittest.cc',
-      'common/gpu/gpu_channel_manager_unittest.cc',
       'common/host_discardable_shared_memory_manager_unittest.cc',
       'common/host_shared_bitmap_manager_unittest.cc',
       'common/indexed_db/indexed_db_key_unittest.cc',
@@ -695,7 +697,6 @@
       'renderer/gpu/render_widget_compositor_unittest.cc',
       'renderer/ico_image_decoder_unittest.cc',
       'renderer/input/input_event_filter_unittest.cc',
-      'renderer/peripheral_content_heuristic_unittest.cc',
       'renderer/manifest/manifest_parser_unittest.cc',
       'renderer/media/android/media_info_loader_unittest.cc',
       'renderer/media/audio_message_filter_unittest.cc',
@@ -706,6 +707,7 @@
       'renderer/media/video_capture_impl_manager_unittest.cc',
       'renderer/media/video_capture_impl_unittest.cc',
       'renderer/media/video_capture_message_filter_unittest.cc',
+      'renderer/peripheral_content_heuristic_unittest.cc',
       'renderer/raster_worker_pool_unittest.cc',
       'renderer/render_thread_impl_unittest.cc',
       'renderer/render_widget_unittest.cc',
diff --git a/content/gpu/gpu_main.cc b/content/gpu/gpu_main.cc
index 6c7e8af2..973b0a0 100644
--- a/content/gpu/gpu_main.cc
+++ b/content/gpu/gpu_main.cc
@@ -55,7 +55,7 @@
 #if defined(OS_WIN)
 #include "base/win/windows_version.h"
 #include "base/win/scoped_com_initializer.h"
-#include "content/common/gpu/media/dxva_video_decode_accelerator.h"
+#include "content/common/gpu/media/dxva_video_decode_accelerator_win.h"
 #include "sandbox/win/src/sandbox.h"
 #endif
 
diff --git a/content/plugin/plugin_channel.cc b/content/plugin/plugin_channel.cc
index 219f2f15..852d71a2b 100644
--- a/content/plugin/plugin_channel.cc
+++ b/content/plugin/plugin_channel.cc
@@ -253,7 +253,6 @@
                                     OnDestroyInstance)
     IPC_MESSAGE_HANDLER(PluginMsg_GenerateRouteID, OnGenerateRouteID)
     IPC_MESSAGE_HANDLER(PluginProcessMsg_ClearSiteData, OnClearSiteData)
-    IPC_MESSAGE_HANDLER(PluginHostMsg_DidAbortLoading, OnDidAbortLoading)
     IPC_MESSAGE_UNHANDLED(handled = false)
   IPC_END_MESSAGE_MAP()
   DCHECK(handled);
@@ -327,13 +326,4 @@
   Send(new PluginProcessHostMsg_ClearSiteDataResult(success));
 }
 
-void PluginChannel::OnDidAbortLoading(int render_view_id) {
-  for (size_t i = 0; i < plugin_stubs_.size(); ++i) {
-    if (plugin_stubs_[i]->webplugin()->host_render_view_routing_id() ==
-            render_view_id) {
-      plugin_stubs_[i]->delegate()->instance()->CloseStreams();
-    }
-  }
-}
-
 }  // namespace content
diff --git a/content/plugin/webplugin_delegate_stub.cc b/content/plugin/webplugin_delegate_stub.cc
index b7fdf0b..ba53302 100644
--- a/content/plugin/webplugin_delegate_stub.cc
+++ b/content/plugin/webplugin_delegate_stub.cc
@@ -98,8 +98,6 @@
     IPC_MESSAGE_HANDLER(PluginMsg_DidReceiveData, OnDidReceiveData)
     IPC_MESSAGE_HANDLER(PluginMsg_DidFinishLoading, OnDidFinishLoading)
     IPC_MESSAGE_HANDLER(PluginMsg_DidFail, OnDidFail)
-    IPC_MESSAGE_HANDLER(PluginMsg_DidFinishLoadWithReason,
-                        OnDidFinishLoadWithReason)
     IPC_MESSAGE_HANDLER(PluginMsg_SetFocus, OnSetFocus)
     IPC_MESSAGE_HANDLER(PluginMsg_HandleInputEvent, OnHandleInputEvent)
     IPC_MESSAGE_HANDLER(PluginMsg_Paint, OnPaint)
@@ -109,8 +107,6 @@
     IPC_MESSAGE_HANDLER(PluginMsg_GetFormValue, OnGetFormValue)
     IPC_MESSAGE_HANDLER(PluginMsg_UpdateGeometry, OnUpdateGeometry)
     IPC_MESSAGE_HANDLER(PluginMsg_UpdateGeometrySync, OnUpdateGeometry)
-    IPC_MESSAGE_HANDLER(PluginMsg_SendJavaScriptStream,
-                        OnSendJavaScriptStream)
     IPC_MESSAGE_HANDLER(PluginMsg_SetContentAreaFocus, OnSetContentAreaFocus)
 #if defined(OS_WIN) && !defined(USE_AURA)
     IPC_MESSAGE_HANDLER(PluginMsg_ImeCompositionUpdated,
@@ -126,17 +122,6 @@
     IPC_MESSAGE_HANDLER(PluginMsg_ImeCompositionCompleted,
                         OnImeCompositionCompleted)
 #endif
-    IPC_MESSAGE_HANDLER(PluginMsg_DidReceiveManualResponse,
-                        OnDidReceiveManualResponse)
-    IPC_MESSAGE_HANDLER(PluginMsg_DidReceiveManualData, OnDidReceiveManualData)
-    IPC_MESSAGE_HANDLER(PluginMsg_DidFinishManualLoading,
-                        OnDidFinishManualLoading)
-    IPC_MESSAGE_HANDLER(PluginMsg_DidManualLoadFail, OnDidManualLoadFail)
-    IPC_MESSAGE_HANDLER(PluginMsg_HandleURLRequestReply,
-                        OnHandleURLRequestReply)
-    IPC_MESSAGE_HANDLER(PluginMsg_HTTPRangeRequestReply,
-                        OnHTTPRangeRequestReply)
-    IPC_MESSAGE_HANDLER(PluginMsg_FetchURL, OnFetchURL)
     IPC_MESSAGE_UNHANDLED(handled = false)
   IPC_END_MESSAGE_MAP()
 
@@ -246,11 +231,6 @@
   client->DidFail(id);
 }
 
-void WebPluginDelegateStub::OnDidFinishLoadWithReason(
-    const GURL& url, int reason, int notify_id) {
-  delegate_->DidFinishLoadWithReason(url, reason, notify_id);
-}
-
 void WebPluginDelegateStub::OnSetFocus(bool focused) {
   delegate_->SetFocus(focused);
 #if defined(OS_WIN) && !defined(USE_AURA)
@@ -312,13 +292,6 @@
   *success = delegate_->GetFormValue(value);
 }
 
-void WebPluginDelegateStub::OnSendJavaScriptStream(const GURL& url,
-                                                   const std::string& result,
-                                                   bool success,
-                                                   int notify_id) {
-  delegate_->SendJavaScriptStream(url, result, success, notify_id);
-}
-
 void WebPluginDelegateStub::OnSetContentAreaFocus(bool has_focus) {
   if (delegate_)
     delegate_->SetContentAreaHasFocus(has_focus);
@@ -376,61 +349,4 @@
 }
 #endif  // OS_MACOSX
 
-void WebPluginDelegateStub::OnDidReceiveManualResponse(
-    const GURL& url,
-    const PluginMsg_DidReceiveResponseParams& params) {
-  delegate_->DidReceiveManualResponse(url, params.mime_type, params.headers,
-                                      params.expected_length,
-                                      params.last_modified);
-}
-
-void WebPluginDelegateStub::OnDidReceiveManualData(
-    const std::vector<char>& buffer) {
-  delegate_->DidReceiveManualData(&buffer.front(),
-                                  static_cast<int>(buffer.size()));
-}
-
-void WebPluginDelegateStub::OnDidFinishManualLoading() {
-  delegate_->DidFinishManualLoading();
-}
-
-void WebPluginDelegateStub::OnDidManualLoadFail() {
-  delegate_->DidManualLoadFail();
-}
-
-void WebPluginDelegateStub::OnHandleURLRequestReply(
-    unsigned long resource_id, const GURL& url, int notify_id) {
-  WebPluginResourceClient* resource_client =
-      delegate_->CreateResourceClient(resource_id, url, notify_id);
-  webplugin_->OnResourceCreated(resource_id, resource_client);
-}
-
-void WebPluginDelegateStub::OnHTTPRangeRequestReply(
-    unsigned long resource_id, int range_request_id) {
-  WebPluginResourceClient* resource_client =
-      delegate_->CreateSeekableResourceClient(resource_id, range_request_id);
-  webplugin_->OnResourceCreated(resource_id, resource_client);
-}
-
-void WebPluginDelegateStub::OnFetchURL(
-    const PluginMsg_FetchURL_Params& params) {
-  const char* data = NULL;
-  if (params.post_data.size())
-    data = &params.post_data[0];
-
-  delegate_->FetchURL(params.resource_id,
-                      params.notify_id,
-                      params.url,
-                      params.first_party_for_cookies,
-                      params.method,
-                      data,
-                      static_cast<unsigned int>(params.post_data.size()),
-                      Referrer(params.referrer, params.referrer_policy),
-                      params.notify_redirect,
-                      params.is_plugin_src_load,
-                      channel_->renderer_id(),
-                      params.render_frame_id,
-                      webplugin_->host_render_view_routing_id());
-}
-
 }  // namespace content
diff --git a/content/plugin/webplugin_delegate_stub.h b/content/plugin/webplugin_delegate_stub.h
index 63964e1..e150661 100644
--- a/content/plugin/webplugin_delegate_stub.h
+++ b/content/plugin/webplugin_delegate_stub.h
@@ -67,7 +67,6 @@
                         int data_offset);
   void OnDidFinishLoading(int id);
   void OnDidFail(int id);
-  void OnDidFinishLoadWithReason(const GURL& url, int reason, int notify_id);
   void OnSetFocus(bool focused);
   void OnHandleInputEvent(const blink::WebInputEvent* event,
                           bool* handled, WebCursor* cursor);
@@ -75,10 +74,6 @@
   void OnDidPaint();
   void OnUpdateGeometry(const PluginMsg_UpdateGeometry_Param& param);
   void OnGetPluginScriptableObject(int* route_id);
-  void OnSendJavaScriptStream(const GURL& url,
-                              const std::string& result,
-                              bool success,
-                              int notify_id);
   void OnGetFormValue(base::string16* value, bool* success);
 
   void OnSetContentAreaFocus(bool has_focus);
@@ -99,18 +94,6 @@
   void OnImeCompositionCompleted(const base::string16& text);
 #endif
 
-  void OnDidReceiveManualResponse(
-      const GURL& url,
-      const PluginMsg_DidReceiveResponseParams& params);
-  void OnDidReceiveManualData(const std::vector<char>& buffer);
-  void OnDidFinishManualLoading();
-  void OnDidManualLoadFail();
-  void OnHandleURLRequestReply(unsigned long resource_id,
-                               const GURL& url,
-                               int notify_id);
-  void OnHTTPRangeRequestReply(unsigned long resource_id, int range_request_id);
-  void OnFetchURL(const PluginMsg_FetchURL_Params& params);
-
   std::string mime_type_;
   int instance_id_;
 
diff --git a/content/plugin/webplugin_proxy.cc b/content/plugin/webplugin_proxy.cc
index 5bd3d67e..13447907 100644
--- a/content/plugin/webplugin_proxy.cc
+++ b/content/plugin/webplugin_proxy.cc
@@ -269,46 +269,6 @@
   resource_clients_[resource_id] = client;
 }
 
-void WebPluginProxy::HandleURLRequest(const char* url,
-                                      const char* method,
-                                      const char* target,
-                                      const char* buf,
-                                      unsigned int len,
-                                      int notify_id,
-                                      bool popups_allowed,
-                                      bool notify_redirects) {
-  if (!target && base::EqualsCaseInsensitiveASCII(method, "GET")) {
-    // Please refer to https://bugzilla.mozilla.org/show_bug.cgi?id=366082
-    // for more details on this.
-    if (delegate_->GetQuirks() &
-        WebPluginDelegateImpl::PLUGIN_QUIRK_BLOCK_NONSTANDARD_GETURL_REQUESTS) {
-      GURL request_url(url);
-      if (!request_url.SchemeIs(url::kHttpScheme) &&
-          !request_url.SchemeIs(url::kHttpsScheme) &&
-          !request_url.SchemeIs(url::kFtpScheme)) {
-        return;
-      }
-    }
-  }
-
-  PluginHostMsg_URLRequest_Params params;
-  params.url = url;
-  params.method = method;
-  if (target)
-    params.target = std::string(target);
-
-  if (len) {
-    params.buffer.resize(len);
-    memcpy(&params.buffer.front(), buf, len);
-  }
-
-  params.notify_id = notify_id;
-  params.popups_allowed = popups_allowed;
-  params.notify_redirects = notify_redirects;
-
-  Send(new PluginHostMsg_URLRequest(route_id_, params));
-}
-
 void WebPluginProxy::Paint(const gfx::Rect& rect) {
 #if defined(OS_MACOSX)
   if (!windowless_context())
@@ -500,12 +460,6 @@
   Send(new PluginHostMsg_CancelDocumentLoad(route_id_));
 }
 
-void WebPluginProxy::InitiateHTTPRangeRequest(
-    const char* url, const char* range_info, int range_request_id) {
-  Send(new PluginHostMsg_InitiateHTTPRangeRequest(
-      route_id_, url, range_info, range_request_id));
-}
-
 void WebPluginProxy::DidStartLoading() {
   Send(new PluginHostMsg_DidStartLoading(route_id_));
 }
diff --git a/content/plugin/webplugin_proxy.h b/content/plugin/webplugin_proxy.h
index 7e54434..cc000cd 100644
--- a/content/plugin/webplugin_proxy.h
+++ b/content/plugin/webplugin_proxy.h
@@ -66,23 +66,12 @@
                  const std::string& cookie) override;
   std::string GetCookies(const GURL& url,
                          const GURL& first_party_for_cookies) override;
-  void HandleURLRequest(const char* url,
-                        const char* method,
-                        const char* target,
-                        const char* buf,
-                        unsigned int len,
-                        int notify_id,
-                        bool popups_allowed,
-                        bool notify_redirects) override;
   void UpdateGeometry(const gfx::Rect& window_rect,
                       const gfx::Rect& clip_rect,
                       const TransportDIB::Handle& windowless_buffer0,
                       const TransportDIB::Handle& windowless_buffer1,
                       int windowless_buffer_index);
   void CancelDocumentLoad() override;
-  void InitiateHTTPRangeRequest(const char* url,
-                                const char* range_info,
-                                int range_request_id) override;
   void DidStartLoading() override;
   void DidStopLoading() override;
   void SetDeferResourceLoading(unsigned long resource_id, bool defer) override;
diff --git a/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java b/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java
index de62b51..db35349 100644
--- a/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java
+++ b/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java
@@ -2561,11 +2561,15 @@
 
     @SuppressWarnings("unused")
     @CalledByNative
-    private void showPastePopupWithFeedback(int x, int y) {
+    private boolean showPastePopupWithFeedback(int x, int y) {
         // TODO(jdduke): Remove this when there is a better signal that long press caused
         // showing of the paste popup. See http://crbug.com/150151.
         if (showPastePopup(x, y)) {
             mContainerView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
+            if (mWebContents != null) mWebContents.onContextMenuOpened();
+            return true;
+        } else {
+            return false;
         }
     }
 
@@ -2594,6 +2598,11 @@
                     mWebContents.paste();
                     dismissTextHandles();
                 }
+
+                @Override
+                public void onDismiss() {
+                    if (mWebContents != null) mWebContents.onContextMenuClosed();
+                }
             };
             if (supportsFloatingActionMode()) {
                 mPastePopupMenu = new FloatingPastePopupMenu(getContainerView(), delegate);
diff --git a/content/public/android/java/src/org/chromium/content/browser/input/FloatingPastePopupMenu.java b/content/public/android/java/src/org/chromium/content/browser/input/FloatingPastePopupMenu.java
index 7f7723b..3423dfa3 100644
--- a/content/public/android/java/src/org/chromium/content/browser/input/FloatingPastePopupMenu.java
+++ b/content/public/android/java/src/org/chromium/content/browser/input/FloatingPastePopupMenu.java
@@ -162,6 +162,7 @@
             @Override
             public void onDestroyActionMode() {
                 mActionMode = null;
+                mDelegate.onDismiss();
             }
 
             @Override
diff --git a/content/public/android/java/src/org/chromium/content/browser/input/LegacyPastePopupMenu.java b/content/public/android/java/src/org/chromium/content/browser/input/LegacyPastePopupMenu.java
index 39ee0e6..abe69273 100644
--- a/content/public/android/java/src/org/chromium/content/browser/input/LegacyPastePopupMenu.java
+++ b/content/public/android/java/src/org/chromium/content/browser/input/LegacyPastePopupMenu.java
@@ -14,6 +14,7 @@
 import android.view.ViewGroup;
 import android.view.ViewGroup.LayoutParams;
 import android.widget.PopupWindow;
+import android.widget.PopupWindow.OnDismissListener;
 
 /**
  * Paste popup implementation based on TextView.PastePopupMenu.
@@ -33,7 +34,7 @@
     private final int mLineOffsetY;
     private final int mWidthOffsetX;
 
-    public LegacyPastePopupMenu(View parent, PastePopupMenuDelegate delegate) {
+    public LegacyPastePopupMenu(View parent, final PastePopupMenuDelegate delegate) {
         mParent = parent;
         mDelegate = delegate;
         mContext = parent.getContext();
@@ -44,6 +45,12 @@
 
         mContainer.setWidth(ViewGroup.LayoutParams.WRAP_CONTENT);
         mContainer.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT);
+        mContainer.setOnDismissListener(new OnDismissListener() {
+            @Override
+            public void onDismiss() {
+                delegate.onDismiss();
+            }
+        });
 
         final int[] popupLayoutAttrs = {
                 android.R.attr.textEditPasteWindowLayout,
diff --git a/content/public/android/java/src/org/chromium/content/browser/input/PastePopupMenu.java b/content/public/android/java/src/org/chromium/content/browser/input/PastePopupMenu.java
index 6b948968..051379e 100644
--- a/content/public/android/java/src/org/chromium/content/browser/input/PastePopupMenu.java
+++ b/content/public/android/java/src/org/chromium/content/browser/input/PastePopupMenu.java
@@ -16,6 +16,11 @@
          * Called to initiate a paste after the popup has been tapped.
          */
         void paste();
+
+        /**
+         * Called when the popup menu is dismissed.
+         */
+        void onDismiss();
     }
 
     /**
diff --git a/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java b/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java
index 6ecb3f8..e2d6cef 100644
--- a/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java
+++ b/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java
@@ -84,6 +84,8 @@
     // Lazily created proxy observer for handling all Java-based WebContentsObservers.
     private WebContentsObserverProxy mObserverProxy;
 
+    private boolean mContextMenuOpened;
+
     private WebContentsImpl(
             long nativeWebContentsAndroid, NavigationController navigationController) {
         mNativeWebContentsAndroid = nativeWebContentsAndroid;
@@ -430,6 +432,24 @@
                 srcRect.top, srcRect.left, srcRect.width(), srcRect.height());
     }
 
+    @Override
+    public void onContextMenuOpened() {
+        mContextMenuOpened = true;
+    }
+
+    @Override
+    public void onContextMenuClosed() {
+        if (!mContextMenuOpened) {
+            return;
+        } else {
+            mContextMenuOpened = false;
+        }
+
+        if (mNativeWebContentsAndroid != 0) {
+            nativeOnContextMenuClosed(mNativeWebContentsAndroid);
+        }
+    }
+
     @CalledByNative
     private void onGetContentBitmapFinished(ContentBitmapCallback callback, Bitmap bitmap,
             int response) {
@@ -494,4 +514,5 @@
     private native void nativeGetContentBitmap(long nativeWebContentsAndroid,
             ContentBitmapCallback callback, Bitmap.Config config, float scale,
             float x, float y, float width, float height);
+    private native void nativeOnContextMenuClosed(long nativeWebContentsAndroid);
 }
diff --git a/content/public/android/java/src/org/chromium/content_public/browser/WebContents.java b/content/public/android/java/src/org/chromium/content_public/browser/WebContents.java
index 919fd1b..4a1729b 100644
--- a/content/public/android/java/src/org/chromium/content_public/browser/WebContents.java
+++ b/content/public/android/java/src/org/chromium/content_public/browser/WebContents.java
@@ -323,6 +323,18 @@
     void removeObserver(WebContentsObserver observer);
 
     /**
+     * Called when context menu gets opened.
+     */
+    void onContextMenuOpened();
+
+    /**
+     * Called when context menu gets closed. Note that closing context menu that is
+     * not triggered by WebContents will still call this. However, it will have no effect
+     * if onContextMenuOpened() isn't called in advance.
+     */
+    void onContextMenuClosed();
+
+    /**
      * @return The character encoding for the current visible page.
      */
     @VisibleForTesting
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 da0544e..eff9d4f 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
@@ -37,22 +37,22 @@
         ChildProcessLauncher.allocateBoundConnectionForTesting(context);
 
         // Verify that the connection is not considered as allocated.
-        assertTrue("Failed connection wasn't released from the allocator.",
-                CriteriaHelper.pollForCriteria(new Criteria() {
-                    @Override
-                    public boolean isSatisfied() {
-                        return ChildProcessLauncher.allocatedConnectionsCountForTesting(
-                                appContext) == 0;
-                    }
-                }));
+        CriteriaHelper.pollForCriteria(new Criteria(
+                "Failed connection wasn't released from the allocator.") {
+            @Override
+            public boolean isSatisfied() {
+                return ChildProcessLauncher.allocatedConnectionsCountForTesting(
+                        appContext) == 0;
+            }
+        });
 
-        assertTrue("Failed connection wasn't released from ChildProcessLauncher.",
-                CriteriaHelper.pollForCriteria(new Criteria() {
-                    @Override
-                    public boolean isSatisfied() {
-                        return ChildProcessLauncher.connectedServicesCountForTesting() == 0;
-                    }
-                }));
+        CriteriaHelper.pollForCriteria(new Criteria(
+                "Failed connection wasn't released from ChildProcessLauncher.") {
+            @Override
+            public boolean isSatisfied() {
+                return ChildProcessLauncher.connectedServicesCountForTesting() == 0;
+            }
+        });
     }
 
     /**
@@ -77,22 +77,22 @@
         assertTrue(connection.crashServiceForTesting());
 
         // Verify that the connection gets cleaned-up.
-        assertTrue("Crashed connection wasn't released from the allocator.",
-                CriteriaHelper.pollForCriteria(new Criteria() {
-                    @Override
-                    public boolean isSatisfied() {
-                        return ChildProcessLauncher.allocatedConnectionsCountForTesting(
-                                appContext) == 0;
-                    }
-                }));
+        CriteriaHelper.pollForCriteria(new Criteria(
+                "Crashed connection wasn't released from the allocator.") {
+            @Override
+            public boolean isSatisfied() {
+                return ChildProcessLauncher.allocatedConnectionsCountForTesting(
+                        appContext) == 0;
+            }
+        });
 
-        assertTrue("Crashed connection wasn't released from ChildProcessLauncher.",
-                CriteriaHelper.pollForCriteria(new Criteria() {
-                    @Override
-                    public boolean isSatisfied() {
-                        return ChildProcessLauncher.connectedServicesCountForTesting() == 0;
-                    }
-                }));
+        CriteriaHelper.pollForCriteria(new Criteria(
+                "Crashed connection wasn't released from ChildProcessLauncher.") {
+            @Override
+            public boolean isSatisfied() {
+                return ChildProcessLauncher.connectedServicesCountForTesting() == 0;
+            }
+        });
     }
 
     /**
@@ -113,42 +113,42 @@
                 new FileDescriptorInfo[0], ChildProcessLauncher.CALLBACK_FOR_RENDERER_PROCESS, 0);
 
         // Verify that the connection completes the setup.
-        assertTrue("The connection wasn't registered in ChildProcessLauncher after setup.",
-                CriteriaHelper.pollForCriteria(new Criteria() {
-                    @Override
-                    public boolean isSatisfied() {
-                        return ChildProcessLauncher.connectedServicesCountForTesting() == 1;
-                    }
-                }));
+        CriteriaHelper.pollForCriteria(new Criteria(
+                "The connection wasn't registered in ChildProcessLauncher after setup.") {
+            @Override
+            public boolean isSatisfied() {
+                return ChildProcessLauncher.connectedServicesCountForTesting() == 1;
+            }
+        });
 
-        assertTrue("The connection failed to get a pid in setup.",
-                CriteriaHelper.pollForCriteria(new Criteria() {
+        CriteriaHelper.pollForCriteria(
+                new Criteria("The connection failed to get a pid in setup.") {
                     @Override
                     public boolean isSatisfied() {
                         return connection.getPid() != 0;
                     }
-                }));
+                });
 
         // Crash the service.
         assertTrue(connection.crashServiceForTesting());
 
         // Verify that the connection gets cleaned-up.
-        assertTrue("Crashed connection wasn't released from the allocator.",
-                CriteriaHelper.pollForCriteria(new Criteria() {
-                    @Override
-                    public boolean isSatisfied() {
-                        return ChildProcessLauncher.allocatedConnectionsCountForTesting(
-                                appContext) == 0;
-                    }
-                }));
+        CriteriaHelper.pollForCriteria(new Criteria(
+                "Crashed connection wasn't released from the allocator.") {
+            @Override
+            public boolean isSatisfied() {
+                return ChildProcessLauncher.allocatedConnectionsCountForTesting(
+                        appContext) == 0;
+            }
+        });
 
-        assertTrue("Crashed connection wasn't released from ChildProcessLauncher.",
-                CriteriaHelper.pollForCriteria(new Criteria() {
-                    @Override
-                    public boolean isSatisfied() {
-                        return ChildProcessLauncher.connectedServicesCountForTesting() == 0;
-                    }
-                }));
+        CriteriaHelper.pollForCriteria(new Criteria(
+                "Crashed connection wasn't released from ChildProcessLauncher.") {
+            @Override
+            public boolean isSatisfied() {
+                return ChildProcessLauncher.connectedServicesCountForTesting() == 0;
+            }
+        });
 
         // Verify that the connection pid remains set after termination.
         assertTrue(connection.getPid() != 0);
@@ -180,51 +180,51 @@
                 new FileDescriptorInfo[0], ChildProcessLauncher.CALLBACK_FOR_RENDERER_PROCESS, 0);
 
         // Verify that the connection completes the setup.
-        assertTrue("The connection wasn't registered in ChildProcessLauncher after setup.",
-                CriteriaHelper.pollForCriteria(new Criteria() {
+        CriteriaHelper.pollForCriteria(
+                new Criteria(
+                        "The connection wasn't registered in ChildProcessLauncher after setup.") {
                     @Override
                     public boolean isSatisfied() {
                         return ChildProcessLauncher.connectedServicesCountForTesting() == 1;
                     }
-                }));
+                });
 
-        assertTrue("The connection failed to get a pid in setup.",
-                CriteriaHelper.pollForCriteria(new Criteria() {
+        CriteriaHelper.pollForCriteria(
+                new Criteria("The connection failed to get a pid in setup.") {
                     @Override
                     public boolean isSatisfied() {
                         return connection.getPid() != 0;
                     }
-                }));
+                });
 
         // Crash the service.
         assertTrue(connection.crashServiceForTesting());
 
         // Verify that a new service is started for the pending spawn.
-        assertTrue("Failed to spawn from queue.",
-                CriteriaHelper.pollForCriteria(new Criteria() {
-                    @Override
-                    public boolean isSatisfied() {
-                        return ChildProcessLauncher.pendingSpawnsCountForTesting() == 0;
-                    }
-                }));
+        CriteriaHelper.pollForCriteria(new Criteria("Failed to spawn from queue.") {
+            @Override
+            public boolean isSatisfied() {
+                return ChildProcessLauncher.pendingSpawnsCountForTesting() == 0;
+            }
+        });
 
-        assertTrue("The connection wasn't allocated for the pending spawn.",
-                CriteriaHelper.pollForCriteria(new Criteria() {
+        CriteriaHelper.pollForCriteria(
+                new Criteria("The connection wasn't allocated for the pending spawn.") {
                     @Override
                     public boolean isSatisfied() {
                         return ChildProcessLauncher.allocatedConnectionsCountForTesting(
                                 appContext) == 1;
                     }
-                }));
+                });
 
         // Verify that the connection completes the setup for the pending spawn.
-        assertTrue("The connection wasn't registered in ChildProcessLauncher after setup.",
-                CriteriaHelper.pollForCriteria(new Criteria() {
-                    @Override
-                    public boolean isSatisfied() {
-                        return ChildProcessLauncher.connectedServicesCountForTesting() == 1;
-                    }
-                }));
+        CriteriaHelper.pollForCriteria(new Criteria(
+                "The connection wasn't registered in ChildProcessLauncher after setup.") {
+            @Override
+            public boolean isSatisfied() {
+                return ChildProcessLauncher.connectedServicesCountForTesting() == 1;
+            }
+        });
     }
 
     private ChildProcessConnectionImpl startConnection() throws InterruptedException {
@@ -234,13 +234,12 @@
                 ChildProcessLauncher.allocateBoundConnectionForTesting(context);
 
         // Wait for the service to connect.
-        assertTrue("The connection wasn't established.",
-                CriteriaHelper.pollForCriteria(new Criteria() {
-                    @Override
-                    public boolean isSatisfied() {
-                        return connection.isConnected();
-                    }
-                }));
+        CriteriaHelper.pollForCriteria(new Criteria("The connection wasn't established.") {
+            @Override
+            public boolean isSatisfied() {
+                return connection.isConnected();
+            }
+        });
         return connection;
     }
 
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/ClipboardTest.java b/content/public/android/javatests/src/org/chromium/content/browser/ClipboardTest.java
index ea036e7..69cdf4d 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/ClipboardTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/ClipboardTest.java
@@ -35,7 +35,7 @@
     protected void setUp() throws Exception {
         super.setUp();
         launchContentShellWithUrl(TEST_PAGE_DATA_URL);
-        assertTrue("Page failed to load", waitForActiveShellToBeDoneLoading());
+        waitForActiveShellToBeDoneLoading();
     }
 
     /**
@@ -60,12 +60,12 @@
         copy(webContents);
 
         // Waits until data has been made available on the Android clipboard.
-        assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return hasPrimaryClip(clipboardManager);
             }
-        }));
+        });
 
         // Verify that the data on the clipboard is what we expect it to be. For Android JB MR2
         // and higher we expect HTML content, for other versions the plain-text representation.
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/ContentViewCoreSelectionTest.java b/content/public/android/javatests/src/org/chromium/content/browser/ContentViewCoreSelectionTest.java
index a7beabc..eb6e769 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/ContentViewCoreSelectionTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/ContentViewCoreSelectionTest.java
@@ -43,12 +43,12 @@
         super.setUp();
 
         launchContentShellWithUrl(DATA_URL);
-        assertTrue("Page failed to load", waitForActiveShellToBeDoneLoading());
+        waitForActiveShellToBeDoneLoading();
 
         mContentViewCore = getContentViewCore();
         assertWaitForPageScaleFactorMatch(1.1f);
-        assertWaitForSelectActionBarVisible(false);
-        assertWaitForPastePopupStatus(false);
+        waitForSelectActionBarVisible(false);
+        waitForPastePopupStatus(false);
     }
 
     @SmallTest
@@ -57,14 +57,14 @@
         requestFocusOnUiThread(true);
 
         DOMUtils.longPressNode(this, mContentViewCore, "textarea");
-        assertWaitForSelectActionBarVisible(true);
+        waitForSelectActionBarVisible(true);
 
         requestFocusOnUiThread(false);
-        assertWaitForSelectActionBarVisible(false);
+        waitForSelectActionBarVisible(false);
         assertFalse(mContentViewCore.hasSelection());
 
         requestFocusOnUiThread(true);
-        assertWaitForSelectActionBarVisible(false);
+        waitForSelectActionBarVisible(false);
         assertFalse(mContentViewCore.hasSelection());
     }
 
@@ -74,21 +74,21 @@
         requestFocusOnUiThread(true);
 
         DOMUtils.longPressNode(this, mContentViewCore, "textarea");
-        assertWaitForSelectActionBarVisible(true);
+        waitForSelectActionBarVisible(true);
         assertTrue(mContentViewCore.hasSelection());
 
         mContentViewCore.preserveSelectionOnNextLossOfFocus();
         requestFocusOnUiThread(false);
-        assertWaitForSelectActionBarVisible(false);
+        waitForSelectActionBarVisible(false);
         assertTrue(mContentViewCore.hasSelection());
 
         requestFocusOnUiThread(true);
-        assertWaitForSelectActionBarVisible(true);
+        waitForSelectActionBarVisible(true);
         assertTrue(mContentViewCore.hasSelection());
 
         // Losing focus yet again should properly clear the selection.
         requestFocusOnUiThread(false);
-        assertWaitForSelectActionBarVisible(false);
+        waitForSelectActionBarVisible(false);
         assertFalse(mContentViewCore.hasSelection());
     }
 
@@ -96,15 +96,15 @@
     @Feature({"TextSelection"})
     public void testSelectionPreservedAfterReshown() throws Throwable {
         DOMUtils.longPressNode(this, mContentViewCore, "textarea");
-        assertWaitForSelectActionBarVisible(true);
+        waitForSelectActionBarVisible(true);
         assertTrue(mContentViewCore.hasSelection());
 
         setVisibileOnUiThread(false);
-        assertWaitForSelectActionBarVisible(false);
+        waitForSelectActionBarVisible(false);
         assertTrue(mContentViewCore.hasSelection());
 
         setVisibileOnUiThread(true);
-        assertWaitForSelectActionBarVisible(true);
+        waitForSelectActionBarVisible(true);
         assertTrue(mContentViewCore.hasSelection());
     }
 
@@ -112,15 +112,15 @@
     @Feature({"TextSelection"})
     public void testSelectionPreservedAfterReattached() throws Throwable {
         DOMUtils.longPressNode(this, mContentViewCore, "textarea");
-        assertWaitForSelectActionBarVisible(true);
+        waitForSelectActionBarVisible(true);
         assertTrue(mContentViewCore.hasSelection());
 
         setAttachedOnUiThread(false);
-        assertWaitForSelectActionBarVisible(false);
+        waitForSelectActionBarVisible(false);
         assertTrue(mContentViewCore.hasSelection());
 
         setAttachedOnUiThread(true);
-        assertWaitForSelectActionBarVisible(true);
+        waitForSelectActionBarVisible(true);
         assertTrue(mContentViewCore.hasSelection());
     }
 
@@ -129,10 +129,10 @@
     public void testPastePopupNotShownOnLongPressingNonEmptyInput() throws Throwable {
         copyStringToClipboard("SampleTextToCopy");
         DOMUtils.longPressNode(this, mContentViewCore, "empty_input_text");
-        assertWaitForPastePopupStatus(true);
+        waitForPastePopupStatus(true);
         DOMUtils.longPressNode(this, mContentViewCore, "input_text");
-        assertWaitForSelectActionBarVisible(true);
-        assertWaitForPastePopupStatus(false);
+        waitForSelectActionBarVisible(true);
+        waitForPastePopupStatus(false);
     }
 
     @SmallTest
@@ -140,9 +140,9 @@
     public void testPastePopupClearedOnTappingEmptyInput() throws Throwable {
         copyStringToClipboard("SampleTextToCopy");
         DOMUtils.longPressNode(this, mContentViewCore, "empty_input_text");
-        assertWaitForPastePopupStatus(true);
+        waitForPastePopupStatus(true);
         DOMUtils.clickNode(this, mContentViewCore, "empty_input_text");
-        assertWaitForPastePopupStatus(false);
+        waitForPastePopupStatus(false);
     }
 
     @SmallTest
@@ -150,9 +150,9 @@
     public void testPastePopupClearedOnTappingNonEmptyInput() throws Throwable {
         copyStringToClipboard("SampleTextToCopy");
         DOMUtils.longPressNode(this, mContentViewCore, "empty_input_text");
-        assertWaitForPastePopupStatus(true);
+        waitForPastePopupStatus(true);
         DOMUtils.clickNode(this, mContentViewCore, "input_text");
-        assertWaitForPastePopupStatus(false);
+        waitForPastePopupStatus(false);
     }
 
     @SmallTest
@@ -160,9 +160,9 @@
     public void testPastePopupClearedOnTappingOutsideInput() throws Throwable {
         copyStringToClipboard("SampleTextToCopy");
         DOMUtils.longPressNode(this, mContentViewCore, "empty_input_text");
-        assertWaitForPastePopupStatus(true);
+        waitForPastePopupStatus(true);
         DOMUtils.clickNode(this, mContentViewCore, "plain_text_2");
-        assertWaitForPastePopupStatus(false);
+        waitForPastePopupStatus(false);
     }
 
     @SmallTest
@@ -170,9 +170,9 @@
     public void testPastePopupClearedOnLongPressingOutsideInput() throws Throwable {
         copyStringToClipboard("SampleTextToCopy");
         DOMUtils.longPressNode(this, mContentViewCore, "empty_input_text");
-        assertWaitForPastePopupStatus(true);
+        waitForPastePopupStatus(true);
         DOMUtils.longPressNode(this, mContentViewCore, "plain_text_2");
-        assertWaitForPastePopupStatus(false);
+        waitForPastePopupStatus(false);
     }
 
     @SmallTest
@@ -180,10 +180,10 @@
     public void testPastePopupNotShownOnLongPressingDisabledInput() throws Throwable {
         copyStringToClipboard("SampleTextToCopy");
         DOMUtils.longPressNode(this, mContentViewCore, "empty_input_text");
-        assertWaitForPastePopupStatus(true);
+        waitForPastePopupStatus(true);
         assertTrue(mContentViewCore.hasInsertion());
         DOMUtils.longPressNode(this, mContentViewCore, "disabled_text");
-        assertWaitForPastePopupStatus(false);
+        waitForPastePopupStatus(false);
         assertFalse(mContentViewCore.hasInsertion());
     }
 
@@ -192,21 +192,21 @@
     public void testPastePopupDismissedOnDestroy() throws Throwable {
         copyStringToClipboard("SampleTextToCopy");
         DOMUtils.longPressNode(this, mContentViewCore, "empty_input_text");
-        assertWaitForPastePopupStatus(true);
+        waitForPastePopupStatus(true);
         ThreadUtils.runOnUiThreadBlocking(new Runnable() {
             @Override
             public void run() {
                 mContentViewCore.destroy();
             }
         });
-        assertWaitForPastePopupStatus(false);
+        waitForPastePopupStatus(false);
     }
 
     @SmallTest
     @Feature({"TextInput"})
     public void testActionBarConfiguredCorrectlyForInput() throws Throwable {
         DOMUtils.longPressNode(this, mContentViewCore, "input_text");
-        assertWaitForSelectActionBarVisible(true);
+        waitForSelectActionBarVisible(true);
         assertTrue(mContentViewCore.hasSelection());
         assertNotNull(mContentViewCore.getSelectActionHandler());
         assertTrue(mContentViewCore.getSelectActionHandler().isSelectionEditable());
@@ -217,7 +217,7 @@
     @Feature({"TextInput"})
     public void testActionBarConfiguredCorrectlyForPassword() throws Throwable {
         DOMUtils.longPressNode(this, mContentViewCore, "input_password");
-        assertWaitForSelectActionBarVisible(true);
+        waitForSelectActionBarVisible(true);
         assertTrue(mContentViewCore.hasSelection());
         assertNotNull(mContentViewCore.getSelectActionHandler());
         assertTrue(mContentViewCore.getSelectActionHandler().isSelectionEditable());
@@ -228,7 +228,7 @@
     @Feature({"TextInput"})
     public void testActionBarConfiguredCorrectlyForPlainText() throws Throwable {
         DOMUtils.longPressNode(this, mContentViewCore, "plain_text_1");
-        assertWaitForSelectActionBarVisible(true);
+        waitForSelectActionBarVisible(true);
         assertTrue(mContentViewCore.hasSelection());
         assertNotNull(mContentViewCore.getSelectActionHandler());
         assertFalse(mContentViewCore.getSelectActionHandler().isSelectionEditable());
@@ -239,7 +239,7 @@
     @Feature({"TextInput"})
     public void testActionBarConfiguredCorrectlyForTextArea() throws Throwable {
         DOMUtils.longPressNode(this, mContentViewCore, "textarea");
-        assertWaitForSelectActionBarVisible(true);
+        waitForSelectActionBarVisible(true);
         assertTrue(mContentViewCore.hasSelection());
         assertNotNull(mContentViewCore.getSelectActionHandler());
         assertTrue(mContentViewCore.getSelectActionHandler().isSelectionEditable());
@@ -250,52 +250,52 @@
     @Feature({"TextInput"})
     public void testSelectActionBarPlainTextCopy() throws Exception {
         DOMUtils.longPressNode(this, mContentViewCore, "plain_text_1");
-        assertWaitForSelectActionBarVisible(true);
+        waitForSelectActionBarVisible(true);
         assertTrue(mContentViewCore.hasSelection());
         assertNotNull(mContentViewCore.getSelectActionHandler());
         selectActionBarCopy();
-        assertClipboardContents(mContentViewCore.getContext(), "SamplePlainTextOne");
+        waitForClipboardContents(mContentViewCore.getContext(), "SamplePlainTextOne");
     }
 
     @SmallTest
     @Feature({"TextInput"})
     public void testSelectActionBarInputCopy() throws Exception {
         DOMUtils.longPressNode(this, mContentViewCore, "input_text");
-        assertWaitForSelectActionBarVisible(true);
+        waitForSelectActionBarVisible(true);
         assertTrue(mContentViewCore.hasSelection());
         assertNotNull(mContentViewCore.getSelectActionHandler());
         selectActionBarCopy();
-        assertClipboardContents(mContentViewCore.getContext(), "SampleInputText");
+        waitForClipboardContents(mContentViewCore.getContext(), "SampleInputText");
     }
 
     @SmallTest
     @Feature({"TextInput"})
     public void testSelectActionBarPasswordCopy() throws Exception {
         DOMUtils.longPressNode(this, mContentViewCore, "plain_text_1");
-        assertWaitForSelectActionBarVisible(true);
+        waitForSelectActionBarVisible(true);
         assertTrue(mContentViewCore.hasSelection());
         assertNotNull(mContentViewCore.getSelectActionHandler());
         selectActionBarCopy();
-        assertClipboardContents(mContentViewCore.getContext(), "SamplePlainTextOne");
+        waitForClipboardContents(mContentViewCore.getContext(), "SamplePlainTextOne");
         DOMUtils.longPressNode(this, mContentViewCore, "input_password");
-        assertWaitForSelectActionBarVisible(true);
+        waitForSelectActionBarVisible(true);
         assertTrue(mContentViewCore.hasSelection());
         assertNotNull(mContentViewCore.getSelectActionHandler());
         selectActionBarCopy();
         // Copy option won't be there for Password, hence no change in Clipboard
         // Validating with previous Clipboard content
-        assertClipboardContents(mContentViewCore.getContext(), "SamplePlainTextOne");
+        waitForClipboardContents(mContentViewCore.getContext(), "SamplePlainTextOne");
     }
 
     @SmallTest
     @Feature({"TextInput"})
     public void testSelectActionBarTextAreaCopy() throws Exception {
         DOMUtils.longPressNode(this, mContentViewCore, "textarea");
-        assertWaitForSelectActionBarVisible(true);
+        waitForSelectActionBarVisible(true);
         assertTrue(mContentViewCore.hasSelection());
         assertNotNull(mContentViewCore.getSelectActionHandler());
         selectActionBarCopy();
-        assertClipboardContents(mContentViewCore.getContext(), "SampleTextArea");
+        waitForClipboardContents(mContentViewCore.getContext(), "SampleTextArea");
     }
 
     @SmallTest
@@ -303,30 +303,30 @@
     public void testSelectActionBarPlainTextCut() throws Exception {
         copyStringToClipboard("SampleTextToCopy");
         DOMUtils.longPressNode(this, mContentViewCore, "plain_text_1");
-        assertWaitForSelectActionBarVisible(true);
+        waitForSelectActionBarVisible(true);
         assertTrue(mContentViewCore.hasSelection());
         assertEquals(mContentViewCore.getSelectedText(), "SamplePlainTextOne");
         assertNotNull(mContentViewCore.getSelectActionHandler());
         selectActionBarCut();
-        assertWaitForSelectActionBarVisible(true);
+        waitForSelectActionBarVisible(true);
         assertTrue(mContentViewCore.hasSelection());
         // Cut option won't be available for plain text.
         // Hence validating previous Clipboard content.
-        assertClipboardContents(mContentViewCore.getContext(), "SampleTextToCopy");
+        waitForClipboardContents(mContentViewCore.getContext(), "SampleTextToCopy");
     }
 
     @SmallTest
     @Feature({"TextInput"})
     public void testSelectActionBarInputCut() throws Exception {
         DOMUtils.longPressNode(this, mContentViewCore, "input_text");
-        assertWaitForSelectActionBarVisible(true);
+        waitForSelectActionBarVisible(true);
         assertTrue(mContentViewCore.hasSelection());
         assertEquals(mContentViewCore.getSelectedText(), "SampleInputText");
         assertNotNull(mContentViewCore.getSelectActionHandler());
         selectActionBarCut();
-        assertWaitForSelectActionBarVisible(false);
+        waitForSelectActionBarVisible(false);
         assertFalse(mContentViewCore.hasSelection());
-        assertClipboardContents(mContentViewCore.getContext(), "SampleInputText");
+        waitForClipboardContents(mContentViewCore.getContext(), "SampleInputText");
         assertEquals(mContentViewCore.getSelectedText(), "");
     }
 
@@ -335,29 +335,29 @@
     public void testSelectActionBarPasswordCut() throws Exception {
         copyStringToClipboard("SampleTextToCopy");
         DOMUtils.longPressNode(this, mContentViewCore, "input_password");
-        assertWaitForSelectActionBarVisible(true);
+        waitForSelectActionBarVisible(true);
         assertTrue(mContentViewCore.hasSelection());
         assertNotNull(mContentViewCore.getSelectActionHandler());
         selectActionBarCut();
-        assertWaitForSelectActionBarVisible(true);
+        waitForSelectActionBarVisible(true);
         assertTrue(mContentViewCore.hasSelection());
         // Cut option won't be there for Password, hence no change in Clipboard
         // Validating with previous Clipboard content
-        assertClipboardContents(mContentViewCore.getContext(), "SampleTextToCopy");
+        waitForClipboardContents(mContentViewCore.getContext(), "SampleTextToCopy");
     }
 
     @SmallTest
     @Feature({"TextInput"})
     public void testSelectActionBarTextAreaCut() throws Exception {
         DOMUtils.longPressNode(this, mContentViewCore, "textarea");
-        assertWaitForSelectActionBarVisible(true);
+        waitForSelectActionBarVisible(true);
         assertTrue(mContentViewCore.hasSelection());
         assertEquals(mContentViewCore.getSelectedText(), "SampleTextArea");
         assertNotNull(mContentViewCore.getSelectActionHandler());
         selectActionBarCut();
-        assertWaitForSelectActionBarVisible(false);
+        waitForSelectActionBarVisible(false);
         assertFalse(mContentViewCore.hasSelection());
-        assertClipboardContents(mContentViewCore.getContext(), "SampleTextArea");
+        waitForClipboardContents(mContentViewCore.getContext(), "SampleTextArea");
         assertEquals(mContentViewCore.getSelectedText(), "");
     }
 
@@ -365,24 +365,24 @@
     @Feature({"TextSelection"})
     public void testSelectActionBarPlainTextSelectAll() throws Exception {
         DOMUtils.longPressNode(this, mContentViewCore, "plain_text_1");
-        assertWaitForSelectActionBarVisible(true);
+        waitForSelectActionBarVisible(true);
         assertTrue(mContentViewCore.hasSelection());
         assertNotNull(mContentViewCore.getSelectActionHandler());
         selectActionBarSelectAll();
         assertTrue(mContentViewCore.hasSelection());
-        assertWaitForSelectActionBarVisible(true);
+        waitForSelectActionBarVisible(true);
     }
 
     @SmallTest
     @Feature({"TextInput"})
     public void testSelectActionBarInputSelectAll() throws Exception {
         DOMUtils.longPressNode(this, mContentViewCore, "input_text");
-        assertWaitForSelectActionBarVisible(true);
+        waitForSelectActionBarVisible(true);
         assertTrue(mContentViewCore.hasSelection());
         assertNotNull(mContentViewCore.getSelectActionHandler());
         selectActionBarSelectAll();
         assertTrue(mContentViewCore.hasSelection());
-        assertWaitForSelectActionBarVisible(true);
+        waitForSelectActionBarVisible(true);
         assertEquals(mContentViewCore.getSelectedText(), "SampleInputText");
     }
 
@@ -390,24 +390,24 @@
     @Feature({"TextInput"})
     public void testSelectActionBarPasswordSelectAll() throws Exception {
         DOMUtils.longPressNode(this, mContentViewCore, "input_password");
-        assertWaitForSelectActionBarVisible(true);
+        waitForSelectActionBarVisible(true);
         assertTrue(mContentViewCore.hasSelection());
         assertNotNull(mContentViewCore.getSelectActionHandler());
         selectActionBarSelectAll();
         assertTrue(mContentViewCore.hasSelection());
-        assertWaitForSelectActionBarVisible(true);
+        waitForSelectActionBarVisible(true);
     }
 
     @SmallTest
     @Feature({"TextInput"})
     public void testSelectActionBarTextAreaSelectAll() throws Exception {
         DOMUtils.longPressNode(this, mContentViewCore, "textarea");
-        assertWaitForSelectActionBarVisible(true);
+        waitForSelectActionBarVisible(true);
         assertTrue(mContentViewCore.hasSelection());
         assertNotNull(mContentViewCore.getSelectActionHandler());
         selectActionBarSelectAll();
         assertTrue(mContentViewCore.hasSelection());
-        assertWaitForSelectActionBarVisible(true);
+        waitForSelectActionBarVisible(true);
         assertEquals(mContentViewCore.getSelectedText(), "SampleTextArea");
     }
 
@@ -415,23 +415,23 @@
     @Feature({"TextSelection", "TextInput"})
     public void testCursorPositionAfterHidingActionMode() throws Exception {
         DOMUtils.longPressNode(this, mContentViewCore, "textarea");
-        assertWaitForSelectActionBarVisible(true);
+        waitForSelectActionBarVisible(true);
         assertTrue(mContentViewCore.hasSelection());
         assertNotNull(mContentViewCore.getSelectActionHandler());
         selectActionBarSelectAll();
         assertTrue(mContentViewCore.hasSelection());
-        assertWaitForSelectActionBarVisible(true);
+        waitForSelectActionBarVisible(true);
         assertEquals(mContentViewCore.getSelectedText(), "SampleTextArea");
         hideSelectActionMode();
-        assertWaitForSelectActionBarVisible(false);
-        assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        waitForSelectActionBarVisible(false);
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return "SampleTextArea".equals(mContentViewCore.getImeAdapterForTest()
                         .getInputConnectionForTest()
                         .getTextBeforeCursor(50, 0));
             }
-        }));
+        });
     }
 
     @SmallTest
@@ -439,12 +439,12 @@
     public void testSelectActionBarPlainTextPaste() throws Exception {
         copyStringToClipboard("SampleTextToCopy");
         DOMUtils.longPressNode(this, mContentViewCore, "plain_text_1");
-        assertWaitForSelectActionBarVisible(true);
+        waitForSelectActionBarVisible(true);
         assertTrue(mContentViewCore.hasSelection());
         assertNotNull(mContentViewCore.getSelectActionHandler());
         selectActionBarPaste();
         DOMUtils.longPressNode(this, mContentViewCore, "plain_text_1");
-        assertWaitForSelectActionBarVisible(true);
+        waitForSelectActionBarVisible(true);
         assertTrue(mContentViewCore.hasSelection());
         // Paste option won't be available for plain text.
         // Hence content won't be changed.
@@ -460,13 +460,13 @@
     public void testSelectActionBarInputPaste() throws Exception {
         copyStringToClipboard("SampleTextToCopy");
         DOMUtils.longPressNode(this, mContentViewCore, "input_text");
-        assertWaitForSelectActionBarVisible(true);
+        waitForSelectActionBarVisible(true);
         assertTrue(mContentViewCore.hasSelection());
         assertNotNull(mContentViewCore.getSelectActionHandler());
         selectActionBarPaste();
         DOMUtils.clickNode(this, mContentViewCore, "plain_text_1");
         DOMUtils.longPressNode(this, mContentViewCore, "input_text");
-        assertWaitForSelectActionBarVisible(true);
+        waitForSelectActionBarVisible(true);
         assertTrue(mContentViewCore.hasSelection());
         assertEquals(mContentViewCore.getSelectedText(), "SampleTextToCopy");
     }
@@ -478,7 +478,7 @@
 
         // Select the password field.
         DOMUtils.longPressNode(this, mContentViewCore, "input_password");
-        assertWaitForSelectActionBarVisible(true);
+        waitForSelectActionBarVisible(true);
         assertTrue(mContentViewCore.hasSelection());
         assertEquals(mContentViewCore.getSelectedText().length(), "SamplePassword".length());
 
@@ -486,14 +486,14 @@
         // "SamplePassword".
         assertNotNull(mContentViewCore.getSelectActionHandler());
         selectActionBarPaste();
-        assertWaitForSelectActionBarVisible(false);
+        waitForSelectActionBarVisible(false);
         assertFalse(mContentViewCore.hasSelection());
 
         // Ensure the new text matches the pasted text. Note that we can't
         // actually compare strings as password field selections only provide
         // a placeholder with the correct length.
         DOMUtils.longPressNode(this, mContentViewCore, "input_password");
-        assertWaitForSelectActionBarVisible(true);
+        waitForSelectActionBarVisible(true);
         assertTrue(mContentViewCore.hasSelection());
         assertEquals(mContentViewCore.getSelectedText().length(), "SamplePassword2".length());
     }
@@ -503,13 +503,13 @@
     public void testSelectActionBarTextAreaPaste() throws Exception {
         copyStringToClipboard("SampleTextToCopy");
         DOMUtils.longPressNode(this, mContentViewCore, "textarea");
-        assertWaitForSelectActionBarVisible(true);
+        waitForSelectActionBarVisible(true);
         assertTrue(mContentViewCore.hasSelection());
         assertNotNull(mContentViewCore.getSelectActionHandler());
         selectActionBarPaste();
         DOMUtils.clickNode(this, mContentViewCore, "plain_text_1");
         DOMUtils.longPressNode(this, mContentViewCore, "textarea");
-        assertWaitForSelectActionBarVisible(true);
+        waitForSelectActionBarVisible(true);
         assertTrue(mContentViewCore.hasSelection());
         assertEquals(mContentViewCore.getSelectedText(), "SampleTextToCopy");
     }
@@ -518,7 +518,7 @@
     @Feature({"TextInput"})
     public void testSelectActionBarSearchAndShareLaunchesNewTask() throws Exception {
         DOMUtils.longPressNode(this, mContentViewCore, "textarea");
-        assertWaitForSelectActionBarVisible(true);
+        waitForSelectActionBarVisible(true);
         assertTrue(mContentViewCore.hasSelection());
         assertNotNull(mContentViewCore.getSelectActionHandler());
         selectActionBarSearch();
@@ -594,9 +594,9 @@
         });
     }
 
-    private void assertClipboardContents(final Context context, final String expectedContents)
+    private void waitForClipboardContents(final Context context, final String expectedContents)
             throws InterruptedException {
-        assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 ClipboardManager clipboardManager =
@@ -605,17 +605,17 @@
                 return clip != null && clip.getItemCount() == 1
                         && TextUtils.equals(clip.getItemAt(0).getText(), expectedContents);
             }
-        }));
+        });
     }
 
-    private void assertWaitForSelectActionBarVisible(
+    private void waitForSelectActionBarVisible(
             final boolean visible) throws InterruptedException {
-        assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return visible == mContentViewCore.isSelectActionBarShowing();
             }
-        }));
+        });
     }
 
     private void setVisibileOnUiThread(final boolean show) {
@@ -664,12 +664,12 @@
         clipboardManager.setPrimaryClip(clip);
     }
 
-    private void assertWaitForPastePopupStatus(final boolean show) throws InterruptedException {
-        assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+    private void waitForPastePopupStatus(final boolean show) throws InterruptedException {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return show == mContentViewCore.isPastePopupShowing();
             }
-        }));
+        });
     }
 }
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/ContentViewLocationTest.java b/content/public/android/javatests/src/org/chromium/content/browser/ContentViewLocationTest.java
index 3d76ef2..8e626c9 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/ContentViewLocationTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/ContentViewLocationTest.java
@@ -50,7 +50,7 @@
         mJavascriptHelper.waitUntilHasValue();
         assertEquals(0, Integer.parseInt(mJavascriptHelper.getJsonResultAndClear()));
 
-        assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
+        CriteriaHelper.pollForCriteria(new Criteria() {
                 @Override
                 public boolean isSatisfied() {
                     mJavascriptHelper.evaluateJavaScriptForTests(getWebContents(), "positionCount");
@@ -61,7 +61,7 @@
                     }
                     return Integer.parseInt(mJavascriptHelper.getJsonResultAndClear()) > 0;
                 }
-        }));
+        });
     }
 
     private void startGeolocationWatchPosition() throws Throwable {
@@ -71,12 +71,12 @@
     }
 
     private void ensureGeolocationRunning(final boolean running) throws Exception {
-        assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
+        CriteriaHelper.pollForCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return mMockLocationProvider.isRunning() == running;
             }
-        }));
+        });
     }
 
     @Override
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/ContentViewPopupZoomerTest.java b/content/public/android/javatests/src/org/chromium/content/browser/ContentViewPopupZoomerTest.java
index 6d72ad1..64b62486 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/ContentViewPopupZoomerTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/ContentViewPopupZoomerTest.java
@@ -26,10 +26,11 @@
         return null;
     }
 
-    private static class PopupShowingCriteria implements Criteria {
+    private static class PopupShowingCriteria extends Criteria {
         private final ViewGroup mView;
         private final boolean mShouldBeShown;
         public PopupShowingCriteria(ViewGroup view, boolean shouldBeShown) {
+            super(shouldBeShown ? "Popup did not get shown." : "Popup shown incorrectly.");
             mView = view;
             mShouldBeShown = shouldBeShown;
         }
@@ -41,9 +42,10 @@
         }
     }
 
-    private static class PopupHasNonZeroDimensionsCriteria implements Criteria {
+    private static class PopupHasNonZeroDimensionsCriteria extends Criteria {
         private final ViewGroup mView;
         public PopupHasNonZeroDimensionsCriteria(ViewGroup view) {
+            super("The zoomer popup has zero dimensions.");
             mView = view;
         }
         @Override
@@ -82,22 +84,19 @@
     @DisabledTest // crbug.com/167045
     public void testPopupZoomerShowsUp() throws InterruptedException, TimeoutException {
         launchContentShellWithUrl(generateTestUrl(100, 15, "clickme"));
-        assertTrue("Page failed to load", waitForActiveShellToBeDoneLoading());
+        waitForActiveShellToBeDoneLoading();
 
         final ContentViewCore viewCore = getContentViewCore();
         final ViewGroup view = viewCore.getContainerView();
 
         // The popup should be hidden before the click.
-        assertTrue("The zoomer popup is shown after load.",
-                CriteriaHelper.pollForCriteria(new PopupShowingCriteria(view, false)));
+        CriteriaHelper.pollForCriteria(new PopupShowingCriteria(view, false));
 
         // Once clicked, the popup should show up.
         DOMUtils.clickNode(this, viewCore, "clickme");
-        assertTrue("The zoomer popup did not show up on click.",
-                CriteriaHelper.pollForCriteria(new PopupShowingCriteria(view, true)));
+        CriteriaHelper.pollForCriteria(new PopupShowingCriteria(view, true));
 
         // The shown popup should have valid dimensions eventually.
-        assertTrue("The zoomer popup has zero dimensions.",
-                CriteriaHelper.pollForCriteria(new PopupHasNonZeroDimensionsCriteria(view)));
+        CriteriaHelper.pollForCriteria(new PopupHasNonZeroDimensionsCriteria(view));
     }
 }
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/ContentViewScrollingTest.java b/content/public/android/javatests/src/org/chromium/content/browser/ContentViewScrollingTest.java
index 0ea171c..a73cf9b 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/ContentViewScrollingTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/ContentViewScrollingTest.java
@@ -102,7 +102,7 @@
 
     private void assertWaitForScroll(final boolean hugLeft, final boolean hugTop)
             throws InterruptedException {
-        assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
+        CriteriaHelper.pollForCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 // Scrolling and flinging don't result in exact coordinates.
@@ -117,7 +117,7 @@
                         : getContentViewCore().getNativeScrollYForTest() > maxThreshold;
                 return xCorrect && yCorrect;
             }
-        }));
+        });
     }
 
     private void fling(final int vx, final int vy) throws Throwable {
@@ -169,7 +169,7 @@
         super.setUp();
 
         launchContentShellWithUrl(LARGE_PAGE);
-        assertTrue("Page failed to load", waitForActiveShellToBeDoneLoading());
+        waitForActiveShellToBeDoneLoading();
         assertWaitForPageScaleFactorMatch(2.0f);
 
         assertEquals(0, getContentViewCore().getNativeScrollXForTest());
@@ -362,11 +362,11 @@
         });
         scrollTo(scrollToX, scrollToY);
         assertWaitForScroll(false, false);
-        assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
+        CriteriaHelper.pollForCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return containerViewInternals.isScrollChanged();
             }
-        }));
+        });
     }
 }
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/GestureDetectorResetTest.java b/content/public/android/javatests/src/org/chromium/content/browser/GestureDetectorResetTest.java
index 853c8a3e..dda203e57e 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/GestureDetectorResetTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/GestureDetectorResetTest.java
@@ -34,14 +34,16 @@
             + "<div id=\"test\">not clicked</div><br/>"
             + "</body></html>");
 
-    private static class NodeContentsIsEqualToCriteria implements Criteria {
+    private static class NodeContentsIsEqualToCriteria extends Criteria {
         private final ContentViewCore mViewCore;
         private final String mNodeId;
         private final String mExpectedContents;
 
         public NodeContentsIsEqualToCriteria(
+                String failureReason,
                 ContentViewCore viewCore,
                 String nodeId, String expectedContents) {
+            super(failureReason);
             mViewCore = viewCore;
             mNodeId = nodeId;
             mExpectedContents = expectedContents;
@@ -68,17 +70,17 @@
             ContentViewCore contentViewCore)
                     throws InterruptedException, Exception, Throwable {
         // Initially the text on the page should say "not clicked".
-        assertTrue("The page contents is invalid " + disambiguation,
-                CriteriaHelper.pollForCriteria(new NodeContentsIsEqualToCriteria(
-                        contentViewCore, "test", "not clicked")));
+        CriteriaHelper.pollForCriteria(new NodeContentsIsEqualToCriteria(
+                "The page contents is invalid " + disambiguation, contentViewCore,
+                "test", "not clicked"));
 
         // Click the button.
         DOMUtils.clickNode(this, contentViewCore, "button");
 
         // After the click, the text on the page should say "clicked".
-        assertTrue("The page contents didn't change after a click " + disambiguation,
-                CriteriaHelper.pollForCriteria(new NodeContentsIsEqualToCriteria(
-                        contentViewCore, "test", "clicked")));
+        CriteriaHelper.pollForCriteria(new NodeContentsIsEqualToCriteria(
+                "The page contents didn't change after a click " + disambiguation,
+                contentViewCore, "test", "clicked"));
     }
 
     /**
@@ -94,7 +96,7 @@
             throws InterruptedException, Exception, Throwable {
         // Load the test page.
         launchContentShellWithUrl(CLICK_TEST_URL);
-        assertTrue("Page failed to load", waitForActiveShellToBeDoneLoading());
+        waitForActiveShellToBeDoneLoading();
 
         final ContentViewCore viewCore = getContentViewCore();
         final TestCallbackHelperContainer viewClient =
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/InterstitialPageTest.java b/content/public/android/javatests/src/org/chromium/content/browser/InterstitialPageTest.java
index f95d749..4ad685a 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/InterstitialPageTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/InterstitialPageTest.java
@@ -63,8 +63,9 @@
         waitForActiveShellToBeDoneLoading();
     }
 
-    private boolean waitForInterstitial(final boolean shouldBeShown) throws InterruptedException {
-        return CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+    private void waitForInterstitial(final boolean shouldBeShown) throws InterruptedException {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria(
+                shouldBeShown ? "Interstitial never shown." : "Interstitial never hidden.") {
             @Override
             public boolean isSatisfied() {
                 return shouldBeShown
@@ -111,11 +112,11 @@
                     }
                 });
 
-        assertTrue("Interstitial never shown.", waitForInterstitial(true));
+        waitForInterstitial(true);
         assertTrue("WebContentsObserver not notified of interstitial showing",
                 observer.isInterstitialShowing());
         TouchCommon.singleClickView(getContentViewCore().getContainerView(), 10, 10);
-        assertTrue("Interstitial never hidden.", waitForInterstitial(false));
+        waitForInterstitial(false);
         assertTrue("WebContentsObserver not notified of interstitial hiding",
                 !observer.isInterstitialShowing());
     }
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/MediaSessionTest.java b/content/public/android/javatests/src/org/chromium/content/browser/MediaSessionTest.java
index 9a9576dd..6932f3e8 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/MediaSessionTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/MediaSessionTest.java
@@ -63,8 +63,8 @@
             mAudioFocusState = AudioManager.AUDIOFOCUS_LOSS;
         }
 
-        public boolean waitForFocusStateChange(final int focusType) throws InterruptedException {
-            return CriteriaHelper.pollForCriteria(new Criteria() {
+        public void waitForFocusStateChange(final int focusType) throws InterruptedException {
+            CriteriaHelper.pollForCriteria(new Criteria() {
                 @Override
                 public boolean isSatisfied() {
                     return getAudioFocusState() == focusType;
@@ -100,19 +100,19 @@
     public void testDontStopEachOther() throws Exception {
         assertTrue(DOMUtils.isMediaPaused(getWebContents(), LONG_AUDIO));
         DOMUtils.playMedia(getWebContents(), LONG_AUDIO);
-        assertTrue(DOMUtils.waitForMediaPlay(getWebContents(), LONG_AUDIO));
+        DOMUtils.waitForMediaPlay(getWebContents(), LONG_AUDIO);
 
         assertTrue(DOMUtils.isMediaPaused(getWebContents(), LONG_VIDEO));
         DOMUtils.playMedia(getWebContents(), LONG_VIDEO);
-        assertTrue(DOMUtils.waitForMediaPlay(getWebContents(), LONG_VIDEO));
+        DOMUtils.waitForMediaPlay(getWebContents(), LONG_VIDEO);
 
         assertTrue(DOMUtils.isMediaPaused(getWebContents(), SHORT_VIDEO));
         DOMUtils.playMedia(getWebContents(), SHORT_VIDEO);
-        assertTrue(DOMUtils.waitForMediaPlay(getWebContents(), SHORT_VIDEO));
+        DOMUtils.waitForMediaPlay(getWebContents(), SHORT_VIDEO);
 
         assertTrue(DOMUtils.isMediaPaused(getWebContents(), SHORT_AUDIO));
         DOMUtils.playMedia(getWebContents(), SHORT_AUDIO);
-        assertTrue(DOMUtils.waitForMediaPlay(getWebContents(), SHORT_AUDIO));
+        DOMUtils.waitForMediaPlay(getWebContents(), SHORT_AUDIO);
 
         assertFalse(DOMUtils.isMediaPaused(getWebContents(), SHORT_AUDIO));
         assertFalse(DOMUtils.isMediaPaused(getWebContents(), LONG_AUDIO));
@@ -128,11 +128,11 @@
         assertEquals(AudioManager.AUDIOFOCUS_GAIN, mAudioFocusChangeListener.getAudioFocusState());
 
         DOMUtils.playMedia(getWebContents(), VERY_SHORT_AUDIO);
-        assertTrue(DOMUtils.waitForMediaPlay(getWebContents(), VERY_SHORT_AUDIO));
+        DOMUtils.waitForMediaPlay(getWebContents(), VERY_SHORT_AUDIO);
 
-        assertTrue(mAudioFocusChangeListener.waitForFocusStateChange(
-                AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK));
-        assertTrue(mAudioFocusChangeListener.waitForFocusStateChange(AudioManager.AUDIOFOCUS_GAIN));
+        mAudioFocusChangeListener.waitForFocusStateChange(
+                AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK);
+        mAudioFocusChangeListener.waitForFocusStateChange(AudioManager.AUDIOFOCUS_GAIN);
     }
 
     @MediumTest
@@ -143,11 +143,11 @@
         assertEquals(AudioManager.AUDIOFOCUS_GAIN, mAudioFocusChangeListener.getAudioFocusState());
 
         DOMUtils.playMedia(getWebContents(), VERY_SHORT_VIDEO);
-        assertTrue(DOMUtils.waitForMediaPlay(getWebContents(), VERY_SHORT_VIDEO));
+        DOMUtils.waitForMediaPlay(getWebContents(), VERY_SHORT_VIDEO);
 
-        assertTrue(mAudioFocusChangeListener.waitForFocusStateChange(
-                AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK));
-        assertTrue(mAudioFocusChangeListener.waitForFocusStateChange(AudioManager.AUDIOFOCUS_GAIN));
+        mAudioFocusChangeListener.waitForFocusStateChange(
+                AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK);
+        mAudioFocusChangeListener.waitForFocusStateChange(AudioManager.AUDIOFOCUS_GAIN);
     }
 
     @SmallTest
@@ -158,9 +158,9 @@
         assertEquals(AudioManager.AUDIOFOCUS_GAIN, mAudioFocusChangeListener.getAudioFocusState());
 
         DOMUtils.playMedia(getWebContents(), LONG_AUDIO);
-        assertTrue(DOMUtils.waitForMediaPlay(getWebContents(), LONG_AUDIO));
+        DOMUtils.waitForMediaPlay(getWebContents(), LONG_AUDIO);
 
-        assertTrue(mAudioFocusChangeListener.waitForFocusStateChange(AudioManager.AUDIOFOCUS_LOSS));
+        mAudioFocusChangeListener.waitForFocusStateChange(AudioManager.AUDIOFOCUS_LOSS);
     }
 
     @SmallTest
@@ -171,9 +171,9 @@
         assertEquals(AudioManager.AUDIOFOCUS_GAIN, mAudioFocusChangeListener.getAudioFocusState());
 
         DOMUtils.playMedia(getWebContents(), LONG_VIDEO);
-        assertTrue(DOMUtils.waitForMediaPlay(getWebContents(), LONG_VIDEO));
+        DOMUtils.waitForMediaPlay(getWebContents(), LONG_VIDEO);
 
-        assertTrue(mAudioFocusChangeListener.waitForFocusStateChange(AudioManager.AUDIOFOCUS_LOSS));
+        mAudioFocusChangeListener.waitForFocusStateChange(AudioManager.AUDIOFOCUS_LOSS);
     }
 
     @SmallTest
@@ -184,13 +184,13 @@
         assertEquals(AudioManager.AUDIOFOCUS_GAIN, mAudioFocusChangeListener.getAudioFocusState());
 
         DOMUtils.playMedia(getWebContents(), SHORT_AUDIO);
-        assertTrue(DOMUtils.waitForMediaPlay(getWebContents(), SHORT_AUDIO));
-        assertTrue(mAudioFocusChangeListener.waitForFocusStateChange(
-                AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK));
+        DOMUtils.waitForMediaPlay(getWebContents(), SHORT_AUDIO);
+        mAudioFocusChangeListener.waitForFocusStateChange(
+                AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK);
 
         DOMUtils.playMedia(getWebContents(), LONG_AUDIO);
-        assertTrue(DOMUtils.waitForMediaPlay(getWebContents(), LONG_AUDIO));
-        assertTrue(mAudioFocusChangeListener.waitForFocusStateChange(AudioManager.AUDIOFOCUS_LOSS));
+        DOMUtils.waitForMediaPlay(getWebContents(), LONG_AUDIO);
+        mAudioFocusChangeListener.waitForFocusStateChange(AudioManager.AUDIOFOCUS_LOSS);
     }
 
     @SmallTest
@@ -201,13 +201,13 @@
         assertEquals(AudioManager.AUDIOFOCUS_GAIN, mAudioFocusChangeListener.getAudioFocusState());
 
         DOMUtils.playMedia(getWebContents(), SHORT_VIDEO);
-        assertTrue(DOMUtils.waitForMediaPlay(getWebContents(), SHORT_VIDEO));
-        assertTrue(mAudioFocusChangeListener.waitForFocusStateChange(
-                AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK));
+        DOMUtils.waitForMediaPlay(getWebContents(), SHORT_VIDEO);
+        mAudioFocusChangeListener.waitForFocusStateChange(
+                AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK);
 
         DOMUtils.playMedia(getWebContents(), LONG_VIDEO);
-        assertTrue(DOMUtils.waitForMediaPlay(getWebContents(), LONG_VIDEO));
-        assertTrue(mAudioFocusChangeListener.waitForFocusStateChange(AudioManager.AUDIOFOCUS_LOSS));
+        DOMUtils.waitForMediaPlay(getWebContents(), LONG_VIDEO);
+        mAudioFocusChangeListener.waitForFocusStateChange(AudioManager.AUDIOFOCUS_LOSS);
     }
 
     @SmallTest
@@ -218,16 +218,16 @@
         assertEquals(AudioManager.AUDIOFOCUS_GAIN, mAudioFocusChangeListener.getAudioFocusState());
 
         DOMUtils.playMedia(getWebContents(), SHORT_AUDIO);
-        assertTrue(DOMUtils.waitForMediaPlay(getWebContents(), SHORT_AUDIO));
+        DOMUtils.waitForMediaPlay(getWebContents(), SHORT_AUDIO);
 
         // Wait for the media to be really playing.
-        assertTrue(mAudioFocusChangeListener.waitForFocusStateChange(
-                AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK));
+        mAudioFocusChangeListener.waitForFocusStateChange(
+                AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK);
 
         mAudioFocusChangeListener.requestAudioFocus(AudioManager.AUDIOFOCUS_GAIN);
         assertEquals(AudioManager.AUDIOFOCUS_GAIN, mAudioFocusChangeListener.getAudioFocusState());
 
-        assertTrue(DOMUtils.waitForMediaPause(getWebContents(), SHORT_AUDIO));
+        DOMUtils.waitForMediaPause(getWebContents(), SHORT_AUDIO);
     }
 
     @SmallTest
@@ -238,16 +238,16 @@
         assertEquals(AudioManager.AUDIOFOCUS_GAIN, mAudioFocusChangeListener.getAudioFocusState());
 
         DOMUtils.playMedia(getWebContents(), SHORT_VIDEO);
-        assertTrue(DOMUtils.waitForMediaPlay(getWebContents(), SHORT_VIDEO));
+        DOMUtils.waitForMediaPlay(getWebContents(), SHORT_VIDEO);
 
         // Wait for the media to be really playing.
-        assertTrue(mAudioFocusChangeListener.waitForFocusStateChange(
-                AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK));
+        mAudioFocusChangeListener.waitForFocusStateChange(
+                AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK);
 
         mAudioFocusChangeListener.requestAudioFocus(AudioManager.AUDIOFOCUS_GAIN);
         assertEquals(AudioManager.AUDIOFOCUS_GAIN, mAudioFocusChangeListener.getAudioFocusState());
 
-        assertTrue(DOMUtils.waitForMediaPause(getWebContents(), SHORT_VIDEO));
+        DOMUtils.waitForMediaPause(getWebContents(), SHORT_VIDEO);
     }
 
     @MediumTest
@@ -258,15 +258,15 @@
         assertEquals(AudioManager.AUDIOFOCUS_GAIN, mAudioFocusChangeListener.getAudioFocusState());
 
         DOMUtils.playMedia(getWebContents(), LONG_AUDIO);
-        assertTrue(DOMUtils.waitForMediaPlay(getWebContents(), LONG_AUDIO));
+        DOMUtils.waitForMediaPlay(getWebContents(), LONG_AUDIO);
 
         // Wait for the media to be really playing.
-        assertTrue(mAudioFocusChangeListener.waitForFocusStateChange(AudioManager.AUDIOFOCUS_LOSS));
+        mAudioFocusChangeListener.waitForFocusStateChange(AudioManager.AUDIOFOCUS_LOSS);
 
         mAudioFocusChangeListener.requestAudioFocus(AudioManager.AUDIOFOCUS_GAIN);
         assertEquals(AudioManager.AUDIOFOCUS_GAIN, mAudioFocusChangeListener.getAudioFocusState());
 
-        assertTrue(DOMUtils.waitForMediaPause(getWebContents(), LONG_AUDIO));
+        DOMUtils.waitForMediaPause(getWebContents(), LONG_AUDIO);
     }
 
     @SmallTest
@@ -277,15 +277,15 @@
         assertEquals(AudioManager.AUDIOFOCUS_GAIN, mAudioFocusChangeListener.getAudioFocusState());
 
         DOMUtils.playMedia(getWebContents(), LONG_VIDEO);
-        assertTrue(DOMUtils.waitForMediaPlay(getWebContents(), LONG_VIDEO));
+        DOMUtils.waitForMediaPlay(getWebContents(), LONG_VIDEO);
 
         // Wait for the media to be really playing.
-        assertTrue(mAudioFocusChangeListener.waitForFocusStateChange(AudioManager.AUDIOFOCUS_LOSS));
+        mAudioFocusChangeListener.waitForFocusStateChange(AudioManager.AUDIOFOCUS_LOSS);
 
         mAudioFocusChangeListener.requestAudioFocus(AudioManager.AUDIOFOCUS_GAIN);
         assertEquals(AudioManager.AUDIOFOCUS_GAIN, mAudioFocusChangeListener.getAudioFocusState());
 
-        assertTrue(DOMUtils.waitForMediaPause(getWebContents(), LONG_VIDEO));
+        DOMUtils.waitForMediaPause(getWebContents(), LONG_VIDEO);
     }
 
     @SmallTest
@@ -296,20 +296,20 @@
         assertEquals(AudioManager.AUDIOFOCUS_GAIN, mAudioFocusChangeListener.getAudioFocusState());
 
         DOMUtils.playMedia(getWebContents(), LONG_AUDIO);
-        assertTrue(DOMUtils.waitForMediaPlay(getWebContents(), LONG_AUDIO));
+        DOMUtils.waitForMediaPlay(getWebContents(), LONG_AUDIO);
         DOMUtils.playMedia(getWebContents(), LONG_VIDEO);
-        assertTrue(DOMUtils.waitForMediaPlay(getWebContents(), LONG_VIDEO));
+        DOMUtils.waitForMediaPlay(getWebContents(), LONG_VIDEO);
 
         // Wait for the media to be really playing.
-        assertTrue(mAudioFocusChangeListener.waitForFocusStateChange(AudioManager.AUDIOFOCUS_LOSS));
+        mAudioFocusChangeListener.waitForFocusStateChange(AudioManager.AUDIOFOCUS_LOSS);
 
         mAudioFocusChangeListener.requestAudioFocus(
                 AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK);
         assertEquals(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK,
                 mAudioFocusChangeListener.getAudioFocusState());
 
-        assertTrue(DOMUtils.waitForMediaPause(getWebContents(), LONG_AUDIO));
-        assertTrue(DOMUtils.waitForMediaPause(getWebContents(), LONG_VIDEO));
+        DOMUtils.waitForMediaPause(getWebContents(), LONG_AUDIO);
+        DOMUtils.waitForMediaPause(getWebContents(), LONG_VIDEO);
     }
 
     @MediumTest
@@ -320,25 +320,25 @@
         assertEquals(AudioManager.AUDIOFOCUS_GAIN, mAudioFocusChangeListener.getAudioFocusState());
 
         DOMUtils.playMedia(getWebContents(), LONG_AUDIO);
-        assertTrue(DOMUtils.waitForMediaPlay(getWebContents(), LONG_AUDIO));
+        DOMUtils.waitForMediaPlay(getWebContents(), LONG_AUDIO);
         DOMUtils.playMedia(getWebContents(), LONG_VIDEO);
-        assertTrue(DOMUtils.waitForMediaPlay(getWebContents(), LONG_VIDEO));
+        DOMUtils.waitForMediaPlay(getWebContents(), LONG_VIDEO);
 
         // Wait for the media to be really playing.
-        assertTrue(mAudioFocusChangeListener.waitForFocusStateChange(AudioManager.AUDIOFOCUS_LOSS));
+        mAudioFocusChangeListener.waitForFocusStateChange(AudioManager.AUDIOFOCUS_LOSS);
 
         mAudioFocusChangeListener.requestAudioFocus(
                 AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK);
         assertEquals(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK,
                 mAudioFocusChangeListener.getAudioFocusState());
 
-        assertTrue(DOMUtils.waitForMediaPause(getWebContents(), LONG_AUDIO));
-        assertTrue(DOMUtils.waitForMediaPause(getWebContents(), LONG_VIDEO));
+        DOMUtils.waitForMediaPause(getWebContents(), LONG_AUDIO);
+        DOMUtils.waitForMediaPause(getWebContents(), LONG_VIDEO);
 
         mAudioFocusChangeListener.abandonAudioFocus();
 
-        assertTrue(DOMUtils.waitForMediaPlay(getWebContents(), LONG_AUDIO));
-        assertTrue(DOMUtils.waitForMediaPlay(getWebContents(), LONG_VIDEO));
+        DOMUtils.waitForMediaPlay(getWebContents(), LONG_AUDIO);
+        DOMUtils.waitForMediaPlay(getWebContents(), LONG_VIDEO);
     }
 
     @MediumTest
@@ -349,23 +349,23 @@
         assertEquals(AudioManager.AUDIOFOCUS_GAIN, mAudioFocusChangeListener.getAudioFocusState());
 
         DOMUtils.playMedia(getWebContents(), LONG_AUDIO);
-        assertTrue(DOMUtils.waitForMediaPlay(getWebContents(), LONG_AUDIO));
+        DOMUtils.waitForMediaPlay(getWebContents(), LONG_AUDIO);
         DOMUtils.playMedia(getWebContents(), LONG_VIDEO);
-        assertTrue(DOMUtils.waitForMediaPlay(getWebContents(), LONG_VIDEO));
+        DOMUtils.waitForMediaPlay(getWebContents(), LONG_VIDEO);
 
         // Wait for the media to be really playing.
-        assertTrue(mAudioFocusChangeListener.waitForFocusStateChange(AudioManager.AUDIOFOCUS_LOSS));
+        mAudioFocusChangeListener.waitForFocusStateChange(AudioManager.AUDIOFOCUS_LOSS);
 
         mAudioFocusChangeListener.requestAudioFocus(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
         assertEquals(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT,
                 mAudioFocusChangeListener.getAudioFocusState());
 
-        assertTrue(DOMUtils.waitForMediaPause(getWebContents(), LONG_AUDIO));
-        assertTrue(DOMUtils.waitForMediaPause(getWebContents(), LONG_VIDEO));
+        DOMUtils.waitForMediaPause(getWebContents(), LONG_AUDIO);
+        DOMUtils.waitForMediaPause(getWebContents(), LONG_VIDEO);
 
         mAudioFocusChangeListener.abandonAudioFocus();
 
-        assertTrue(DOMUtils.waitForMediaPlay(getWebContents(), LONG_AUDIO));
-        assertTrue(DOMUtils.waitForMediaPlay(getWebContents(), LONG_VIDEO));
+        DOMUtils.waitForMediaPlay(getWebContents(), LONG_AUDIO);
+        DOMUtils.waitForMediaPlay(getWebContents(), LONG_VIDEO);
     }
 }
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/ScreenOrientationListenerTest.java b/content/public/android/javatests/src/org/chromium/content/browser/ScreenOrientationListenerTest.java
index 1d1ebcc..fb55de2 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/ScreenOrientationListenerTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/ScreenOrientationListenerTest.java
@@ -127,7 +127,13 @@
         });
         getInstrumentation().waitForIdleSync();
 
-        CriteriaHelper.pollForCriteria(criteria);
+        try {
+            CriteriaHelper.pollForCriteria(criteria);
+        } catch (AssertionError e) {
+            // This should not be here but the Criteria does not support cases where the orientation
+            // is not being changed (i.e. where the Natural orientation matches the one you are
+            // locking to).  crbug.com/565587
+        }
     }
 
     @Override
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/ScreenOrientationProviderTest.java b/content/public/android/javatests/src/org/chromium/content/browser/ScreenOrientationProviderTest.java
index 75d36244..0a95dbd 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/ScreenOrientationProviderTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/ScreenOrientationProviderTest.java
@@ -103,7 +103,7 @@
     /**
      * Call |lockOrientation| and wait for an orientation change.
      */
-    private boolean lockOrientationAndWait(final int orientations) throws InterruptedException {
+    private void lockOrientationAndWait(final int orientations) throws InterruptedException {
         OrientationChangeObserverCriteria criteria =
                 new OrientationChangeObserverCriteria(mObserver);
 
@@ -115,7 +115,13 @@
         });
         getInstrumentation().waitForIdleSync();
 
-        return CriteriaHelper.pollForCriteria(criteria);
+        try {
+            CriteriaHelper.pollForCriteria(criteria);
+        } catch (AssertionError e) {
+            // This should not be here but the Criteria does not support cases where the orientation
+            // is not being changed (i.e. where the Natural orientation matches the one you are
+            // locking to).  crbug.com/565587
+        }
     }
 
     @Override
@@ -145,7 +151,13 @@
         lockOrientationAndWait(ScreenOrientationValues.PORTRAIT_PRIMARY);
 
         // Make sure mObserver is updated before we start the tests.
-        CriteriaHelper.pollForCriteria(criteria);
+        try {
+            CriteriaHelper.pollForCriteria(criteria);
+        } catch (AssertionError e) {
+            // This should not be here but the Criteria does not support cases where the orientation
+            // is not being changed (i.e. where the Natural orientation matches the one you are
+            // locking to).  crbug.com/565587
+        }
     }
 
     @Override
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/TestsJavaScriptEvalTest.java b/content/public/android/javatests/src/org/chromium/content/browser/TestsJavaScriptEvalTest.java
index 0eed6b8..29b7b41 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/TestsJavaScriptEvalTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/TestsJavaScriptEvalTest.java
@@ -33,7 +33,7 @@
     public void testJavaScriptEvalIsCorrectlyOrdered()
             throws InterruptedException, Exception, Throwable {
         launchContentShellWithUrl(JSTEST_URL);
-        assertTrue("Page failed to load", waitForActiveShellToBeDoneLoading());
+        waitForActiveShellToBeDoneLoading();
 
         final WebContents webContents = getWebContents();
         for (int i = 0; i < 30; ++i) {
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/VibrationManagerImplTest.java b/content/public/android/javatests/src/org/chromium/content/browser/VibrationManagerImplTest.java
index 634d76bd..2613065 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/VibrationManagerImplTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/VibrationManagerImplTest.java
@@ -60,7 +60,7 @@
     protected void setUp() throws Exception {
         super.setUp();
         launchContentShellWithUrl("about:blank");
-        assertTrue("Page failed to load", waitForActiveShellToBeDoneLoading());
+        waitForActiveShellToBeDoneLoading();
 
         mFakeWrapper = new FakeAndroidVibratorWrapper();
         VibrationManagerImpl.setVibratorWrapperForTesting(mFakeWrapper);
@@ -80,12 +80,12 @@
         loadNewShell(URL_VIBRATOR_VIBRATE);
 
         // Waits until VibrationManagerImpl.Vibrate() got called.
-        assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return mFakeWrapper.mMilliSeconds != -1;
             }
-        }));
+        });
 
         assertEquals(
                 "Did not get vibrate mMilliSeconds correctly", 3000, mFakeWrapper.mMilliSeconds);
@@ -102,12 +102,12 @@
         loadNewShell(URL_VIBRATOR_CANCEL);
 
         // Waits until VibrationManagerImpl.Cancel() got called.
-        assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return mFakeWrapper.mCancelled;
             }
-        }));
+        });
 
         assertTrue("Did not get cancelled", mFakeWrapper.mCancelled);
     }
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/input/AdapterInputConnectionTest.java b/content/public/android/javatests/src/org/chromium/content/browser/input/AdapterInputConnectionTest.java
index 636129f..83fbf8eb 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/input/AdapterInputConnectionTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/input/AdapterInputConnectionTest.java
@@ -31,7 +31,7 @@
     public void setUp() throws Exception {
         super.setUp();
         launchContentShellWithUrl("about:blank");
-        assertTrue("Page failed to load", waitForActiveShellToBeDoneLoading());
+        waitForActiveShellToBeDoneLoading();
         mWrapper = new TestInputMethodManagerWrapper(getActivity());
         mImeAdapter = new TestImeAdapter(mWrapper, new TestImeAdapterDelegate());
         mConnection = new AdapterInputConnection(
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/input/ImeTest.java b/content/public/android/javatests/src/org/chromium/content/browser/input/ImeTest.java
index bbb1878..99686a4 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/input/ImeTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/input/ImeTest.java
@@ -69,7 +69,7 @@
         super.setUp();
 
         launchContentShellWithUrl(DATA_URL);
-        assertTrue("Page failed to load", waitForActiveShellToBeDoneLoading());
+        waitForActiveShellToBeDoneLoading();
         mContentViewCore = getContentViewCore();
         mWebContents = getWebContents();
 
@@ -82,8 +82,7 @@
         mCallbackContainer = new TestCallbackHelperContainer(mContentViewCore);
         // TODO(aurimas) remove this wait once crbug.com/179511 is fixed.
         assertWaitForPageScaleFactorMatch(1);
-        assertTrue(DOMUtils.waitForNonZeroNodeBounds(
-                mWebContents, "input_text"));
+        DOMUtils.waitForNonZeroNodeBounds(mWebContents, "input_text");
         DOMUtils.clickNode(this, mContentViewCore, "input_text");
         assertWaitForKeyboardStatus(true);
 
@@ -100,12 +99,17 @@
 
     private void assertNoFurtherStateUpdate(final int index) throws InterruptedException {
         final List<TestImeState> states = mConnectionFactory.getImeStateList();
-        assertFalse(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
-            @Override
-            public boolean isSatisfied() {
-                return states.size() > index;
-            }
-        }));
+        try {
+            CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+                @Override
+                public boolean isSatisfied() {
+                    return states.size() > index;
+                }
+            });
+            fail("Unexpected updates pending");
+        } catch (AssertionError e) {
+            // TODO(tedchoc): This is horrible and should never timeout to determine success.
+        }
     }
 
     @MediumTest
@@ -206,13 +210,14 @@
     private void waitForKeyboardStates(int show, int hide, int restart, Integer[] history)
             throws InterruptedException {
         final String expected = stringifyKeyboardStates(show, hide, restart, history);
-        assertTrue("Expected: {" + expected + "}, Actual: {" + getKeyboardStates() + "}",
-                CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
-                    @Override
-                    public boolean isSatisfied() {
-                        return expected.equals(getKeyboardStates());
-                    }
-                }));
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+            @Override
+            public boolean isSatisfied() {
+                updateFailureReason(
+                        "Expected: {" + expected + "}, Actual: {" + getKeyboardStates() + "}");
+                return expected.equals(getKeyboardStates());
+            }
+        });
     }
 
     private void resetAllStates() {
@@ -329,12 +334,12 @@
         // hide status of IME, so we will just check whether showIme() has been triggered.
         DOMUtils.longPressNode(this, mContentViewCore, "input_text");
         final int newCount = showCount + 2;
-        assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return newCount == mInputMethodManagerWrapper.getShowSoftInputCounter();
             }
-        }));
+        });
     }
 
     private void attachPhysicalKeyboard() {
@@ -390,13 +395,18 @@
 
         detachPhysicalKeyboard();
 
-        // We should not show soft keyboard here because focus has been lost.
-        assertFalse(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
-            @Override
-            public boolean isSatisfied() {
-                return mInputMethodManagerWrapper.isShowWithoutHideOutstanding();
-            }
-        }));
+        try {
+            // We should not show soft keyboard here because focus has been lost.
+            CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+                @Override
+                public boolean isSatisfied() {
+                    return mInputMethodManagerWrapper.isShowWithoutHideOutstanding();
+                }
+            });
+            fail("Keyboard incorrectly showing");
+        } catch (AssertionError e) {
+            // TODO(tedchoc): This is horrible and should never timeout to determine success.
+        }
     }
 
     @SmallTest
@@ -885,23 +895,23 @@
         waitAndVerifyStatesAndCalls(2, "", 0, 0, -1, -1);
 
         DOMUtils.longPressNode(this, mContentViewCore, "input_text");
-        assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return mContentViewCore.isPastePopupShowing();
             }
-        }));
+        });
 
         DOMUtils.clickNode(this, mContentViewCore, "input_text");
         assertWaitForKeyboardStatus(true);
         DOMUtils.longPressNode(this, mContentViewCore, "input_text");
         setComposingText("h", 1);
-        assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return !mContentViewCore.isPastePopupShowing();
             }
-        }));
+        });
         assertFalse(mContentViewCore.hasInsertion());
     }
 
@@ -965,36 +975,36 @@
     }
 
     private void assertWaitForKeyboardStatus(final boolean show) throws InterruptedException {
-        assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 boolean hasConnection = getAdapterInputConnection() != null;
                 return show == mInputMethodManagerWrapper.isShowWithoutHideOutstanding()
                         && show == hasConnection;
             }
-        }));
+        });
     }
 
     private void assertWaitForSelectActionBarStatus(
             final boolean show) throws InterruptedException {
-        assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return show == mContentViewCore.isSelectActionBarShowing();
             }
-        }));
+        });
     }
 
     private void waitAndVerifyStates(final int index, String text, final int selectionStart,
             final int selectionEnd, final int compositionStart, final int compositionEnd)
             throws InterruptedException {
         final List<TestImeState> states = mConnectionFactory.getImeStateList();
-        assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return states.size() > index;
             }
-        }));
+        });
         states.get(index).assertEqualState(
                 text, selectionStart, selectionEnd, compositionStart, compositionEnd);
     }
@@ -1008,16 +1018,17 @@
         // Wait and verify calls to InputMethodManager.
         final Range selection = new Range(selectionStart, selectionEnd);
         final Range composition = new Range(compositionStart, compositionEnd);
-        assertTrue("Actual selection was: " + mInputMethodManagerWrapper.getSelection()
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+            @Override
+            public boolean isSatisfied() {
+                updateFailureReason(
+                        "Actual selection was: " + mInputMethodManagerWrapper.getSelection()
                         + ", and actual composition was: "
-                        + mInputMethodManagerWrapper.getComposition(),
-                CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
-                    @Override
-                    public boolean isSatisfied() {
-                        return mInputMethodManagerWrapper.getSelection().equals(selection)
-                                && mInputMethodManagerWrapper.getComposition().equals(composition);
-                    }
-                }));
+                        + mInputMethodManagerWrapper.getComposition());
+                return mInputMethodManagerWrapper.getSelection().equals(selection)
+                        && mInputMethodManagerWrapper.getComposition().equals(composition);
+            }
+        });
     }
 
     private void resetUpdateStateList() {
@@ -1038,7 +1049,7 @@
 
     private void assertClipboardContents(final Activity activity, final String expectedContents)
             throws InterruptedException {
-        assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 ClipboardManager clipboardManager =
@@ -1047,7 +1058,7 @@
                 return clip != null && clip.getItemCount() == 1
                         && TextUtils.equals(clip.getItemAt(0).getText(), expectedContents);
             }
-        }));
+        });
     }
 
     private ImeAdapter getImeAdapter() {
@@ -1196,7 +1207,7 @@
             throws InterruptedException, TimeoutException {
         DOMUtils.focusNode(mWebContents, id);
         assertWaitForKeyboardStatus(shouldShowKeyboard);
-        assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
+        CriteriaHelper.pollForCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 try {
@@ -1205,7 +1216,7 @@
                     return false;
                 }
             }
-        }));
+        });
         // When we focus another element, the connection may be recreated.
         mConnection = (TestAdapterInputConnection) getAdapterInputConnection();
     }
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/input/SelectPopupTest.java b/content/public/android/javatests/src/org/chromium/content/browser/input/SelectPopupTest.java
index 4142437c..3994efe 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/input/SelectPopupTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/input/SelectPopupTest.java
@@ -40,14 +40,22 @@
             + "</select>"
             + "</body></html>");
 
-    private class PopupShowingCriteria implements Criteria {
+    private class PopupShowingCriteria extends Criteria {
+        public PopupShowingCriteria() {
+            super("The select popup is not showing as expected.");
+        }
+
         @Override
         public boolean isSatisfied() {
             return getContentViewCore().getSelectPopupForTest() != null;
         }
     }
 
-    private class PopupHiddenCriteria implements Criteria {
+    private class PopupHiddenCriteria extends Criteria {
+        public PopupHiddenCriteria() {
+            super("The select popup is not hidden as expected.");
+        }
+
         @Override
         public boolean isSatisfied() {
             return getContentViewCore().getSelectPopupForTest() == null;
@@ -58,7 +66,7 @@
     public void setUp() throws Exception {
         super.setUp();
         launchContentShellWithUrl(SELECT_URL);
-        assertTrue("Page failed to load", waitForActiveShellToBeDoneLoading());
+        waitForActiveShellToBeDoneLoading();
         // TODO(aurimas) remove this wait once crbug.com/179511 is fixed.
         assertWaitForPageScaleFactorMatch(1);
     }
@@ -72,8 +80,7 @@
     @RerunWithUpdatedContainerView
     public void testReloadWhilePopupShowing() throws InterruptedException, Exception, Throwable {
         // The popup should be hidden before the click.
-        assertTrue("The select popup is shown after load.",
-                CriteriaHelper.pollForCriteria(new PopupHiddenCriteria()));
+        CriteriaHelper.pollForCriteria(new PopupHiddenCriteria());
 
         final ContentViewCore viewCore = getContentViewCore();
         final TestCallbackHelperContainer viewClient = new TestCallbackHelperContainer(viewCore);
@@ -81,8 +88,7 @@
 
         // Once clicked, the popup should show up.
         DOMUtils.clickNode(this, viewCore, "select");
-        assertTrue("The select popup did not show up on click.",
-                CriteriaHelper.pollForCriteria(new PopupShowingCriteria()));
+        CriteriaHelper.pollForCriteria(new PopupShowingCriteria());
 
         // Reload the test page.
         int currentCallCount = onPageFinishedHelper.getCallCount();
@@ -97,12 +103,10 @@
                 WAIT_TIMEOUT_SECONDS, TimeUnit.SECONDS);
 
         // The popup should be hidden after the page reload.
-        assertTrue("The select popup did not hide after reload.",
-                CriteriaHelper.pollForCriteria(new PopupHiddenCriteria()));
+        CriteriaHelper.pollForCriteria(new PopupHiddenCriteria());
 
         // Click the select and wait for the popup to show.
         DOMUtils.clickNode(this, viewCore, "select");
-        assertTrue("The select popup did not show on click after reload.",
-                CriteriaHelper.pollForCriteria(new PopupShowingCriteria()));
+        CriteriaHelper.pollForCriteria(new PopupShowingCriteria());
     }
 }
diff --git a/content/public/android/javatests/src/org/chromium/content/common/CleanupReferenceTest.java b/content/public/android/javatests/src/org/chromium/content/common/CleanupReferenceTest.java
index 602d2f6..29a9060 100644
--- a/content/public/android/javatests/src/org/chromium/content/common/CleanupReferenceTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/common/CleanupReferenceTest.java
@@ -66,12 +66,12 @@
         // Ensure compiler / instrumentation does not strip out the assignment.
         assertTrue(instance == null);
         collectGarbage();
-        assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
+        CriteriaHelper.pollForCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return sObjectCount.get() == 0;
             }
-        }));
+        });
     }
 
     @SuppressFBWarnings("UC_USELESS_OBJECT")
@@ -95,12 +95,12 @@
         // to be GC'ed only when building using GN.
         assertTrue(sObjectCount.get() != -1);
         collectGarbage();
-        assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
+        CriteriaHelper.pollForCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return sObjectCount.get() == 0;
             }
-        }));
+        });
     }
 
 }
diff --git a/content/public/browser/android/content_view_core.h b/content/public/browser/android/content_view_core.h
index e904036..5f487f8a 100644
--- a/content/public/browser/android/content_view_core.h
+++ b/content/public/browser/android/content_view_core.h
@@ -48,7 +48,7 @@
   virtual ui::ViewAndroid* GetViewAndroid() const = 0;
   virtual ui::WindowAndroid* GetWindowAndroid() const = 0;
   virtual const scoped_refptr<cc::Layer>& GetLayer() const = 0;
-  virtual void ShowPastePopup(int x, int y) = 0;
+  virtual bool ShowPastePopup(int x, int y) = 0;
 
   // Request a scaled content readback. The result is passed through the
   // callback. The boolean parameter indicates whether the readback was a
diff --git a/content/public/common/common_param_traits_macros.h b/content/public/common/common_param_traits_macros.h
index 48ba994a..f71d867 100644
--- a/content/public/common/common_param_traits_macros.h
+++ b/content/public/common/common_param_traits_macros.h
@@ -138,9 +138,6 @@
   IPC_STRUCT_TRAITS_MEMBER(application_cache_enabled)
   IPC_STRUCT_TRAITS_MEMBER(tabs_to_links)
   IPC_STRUCT_TRAITS_MEMBER(hyperlink_auditing_enabled)
-  IPC_STRUCT_TRAITS_MEMBER(is_online)
-  IPC_STRUCT_TRAITS_MEMBER(net_info_connection_type)
-  IPC_STRUCT_TRAITS_MEMBER(net_info_max_bandwidth_mbps)
   IPC_STRUCT_TRAITS_MEMBER(allow_universal_access_from_file_urls)
   IPC_STRUCT_TRAITS_MEMBER(allow_file_access_from_file_urls)
   IPC_STRUCT_TRAITS_MEMBER(webaudio_enabled)
@@ -155,7 +152,6 @@
   IPC_STRUCT_TRAITS_MEMBER(privileged_webgl_extensions_enabled)
   IPC_STRUCT_TRAITS_MEMBER(webgl_errors_to_console_enabled)
   IPC_STRUCT_TRAITS_MEMBER(mock_scrollbars_enabled)
-  IPC_STRUCT_TRAITS_MEMBER(asynchronous_spell_checking_enabled)
   IPC_STRUCT_TRAITS_MEMBER(unified_textchecker_enabled)
   IPC_STRUCT_TRAITS_MEMBER(accelerated_2d_canvas_enabled)
   IPC_STRUCT_TRAITS_MEMBER(minimum_accelerated_2d_canvas_size)
diff --git a/content/public/common/content_switches.cc b/content/public/common/content_switches.cc
index 35708aea..0077b5f 100644
--- a/content/public/common/content_switches.cc
+++ b/content/public/common/content_switches.cc
@@ -405,9 +405,6 @@
 // also applys to workers.
 const char kEnablePreciseMemoryInfo[] = "enable-precise-memory-info";
 
-// Enables payloads for received push messages when using the W3C Push API.
-const char kEnablePushMessagePayload[] = "enable-push-message-payload";
-
 // Enables RGBA_4444 textures.
 const char kEnableRGBA4444Textures[] = "enable-rgba-4444-textures";
 
diff --git a/content/public/common/content_switches.h b/content/public/common/content_switches.h
index 2533f42a..987ef41 100644
--- a/content/public/common/content_switches.h
+++ b/content/public/common/content_switches.h
@@ -124,7 +124,6 @@
 CONTENT_EXPORT extern const char kEnablePinch[];
 CONTENT_EXPORT extern const char kEnablePluginPlaceholderTesting[];
 CONTENT_EXPORT extern const char kEnablePreciseMemoryInfo[];
-CONTENT_EXPORT extern const char kEnablePushMessagePayload[];
 CONTENT_EXPORT extern const char kEnableRGBA4444Textures[];
 CONTENT_EXPORT extern const char kEnableSandboxLogging[];
 extern const char kEnableSkiaBenchmarking[];
diff --git a/content/public/common/web_preferences.cc b/content/public/common/web_preferences.cc
index c6023b4d..a86de33b 100644
--- a/content/public/common/web_preferences.cc
+++ b/content/public/common/web_preferences.cc
@@ -96,11 +96,6 @@
       tabs_to_links(true),
       caret_browsing_enabled(false),
       hyperlink_auditing_enabled(true),
-      is_online(true),
-      net_info_connection_type(net::NetworkChangeNotifier::CONNECTION_NONE),
-      net_info_max_bandwidth_mbps(
-          net::NetworkChangeNotifier::GetMaxBandwidthForConnectionSubtype(
-              net::NetworkChangeNotifier::SUBTYPE_NONE)),
       allow_universal_access_from_file_urls(false),
       allow_file_access_from_file_urls(false),
       webaudio_enabled(false),
@@ -113,7 +108,6 @@
       privileged_webgl_extensions_enabled(false),
       webgl_errors_to_console_enabled(true),
       mock_scrollbars_enabled(false),
-      asynchronous_spell_checking_enabled(true),
       unified_textchecker_enabled(false),
       accelerated_2d_canvas_enabled(false),
       minimum_accelerated_2d_canvas_size(257 * 256),
diff --git a/content/public/common/web_preferences.h b/content/public/common/web_preferences.h
index 0378cd7..eb8f77e 100644
--- a/content/public/common/web_preferences.h
+++ b/content/public/common/web_preferences.h
@@ -11,7 +11,6 @@
 
 #include "base/strings/string16.h"
 #include "content/common/content_export.h"
-#include "net/base/network_change_notifier.h"
 #include "ui/base/touch/touch_device.h"
 #include "url/gurl.h"
 
@@ -102,9 +101,6 @@
   bool tabs_to_links;
   bool caret_browsing_enabled;
   bool hyperlink_auditing_enabled;
-  bool is_online;
-  net::NetworkChangeNotifier::ConnectionType net_info_connection_type;
-  double net_info_max_bandwidth_mbps;
   bool allow_universal_access_from_file_urls;
   bool allow_file_access_from_file_urls;
   bool webaudio_enabled;
@@ -117,7 +113,6 @@
   bool privileged_webgl_extensions_enabled;
   bool webgl_errors_to_console_enabled;
   bool mock_scrollbars_enabled;
-  bool asynchronous_spell_checking_enabled;
   bool unified_textchecker_enabled;
   bool accelerated_2d_canvas_enabled;
   int minimum_accelerated_2d_canvas_size;
diff --git a/content/public/renderer/render_frame.h b/content/public/renderer/render_frame.h
index 82caa92..2011c4e6 100644
--- a/content/public/renderer/render_frame.h
+++ b/content/public/renderer/render_frame.h
@@ -189,6 +189,9 @@
   // Whether or not this frame is using Lo-Fi.
   virtual bool IsUsingLoFi() const = 0;
 
+  // Whether or not this frame is currently pasting.
+  virtual bool IsPasting() const = 0;
+
  protected:
   ~RenderFrame() override {}
 
diff --git a/content/public/renderer/render_view.h b/content/public/renderer/render_view.h
index dcf1de4..1f0a235 100644
--- a/content/public/renderer/render_view.h
+++ b/content/public/renderer/render_view.h
@@ -24,6 +24,7 @@
 class WebURLRequest;
 class WebView;
 struct WebContextMenuData;
+struct WebRect;
 }
 
 namespace gfx {
@@ -123,6 +124,13 @@
                                       bool animate) = 0;
 #endif
 
+  // Converts the |rect| from Blink's Viewport coordinates to the
+  // coordinates in the native window used to display the content, in
+  // DIP.  They're identical in tradional world, but will differ when
+  // use-zoom-for-dsf feature is eanbled, and Viewport coordinates
+  // becomes DSF times larger than window coordinates.
+  virtual void convertViewportToWindow(blink::WebRect* rect) = 0;
+
  protected:
   ~RenderView() override {}
 
diff --git a/content/public/test/android/javatests/src/org/chromium/content/browser/test/NativeLibraryTestBase.java b/content/public/test/android/javatests/src/org/chromium/content/browser/test/NativeLibraryTestBase.java
index 86cc0ec..b4528ed 100644
--- a/content/public/test/android/javatests/src/org/chromium/content/browser/test/NativeLibraryTestBase.java
+++ b/content/public/test/android/javatests/src/org/chromium/content/browser/test/NativeLibraryTestBase.java
@@ -36,7 +36,7 @@
         assertFalse(ThreadUtils.runningOnUiThread());
 
         try {
-            assertTrue(ApplicationUtils.waitForLibraryDependencies(getInstrumentation()));
+            ApplicationUtils.waitForLibraryDependencies(getInstrumentation());
         } catch (InterruptedException e) {
             fail("Library dependencies were never initialized.");
         }
diff --git a/content/public/test/android/javatests/src/org/chromium/content/browser/test/util/ApplicationUtils.java b/content/public/test/android/javatests/src/org/chromium/content/browser/test/util/ApplicationUtils.java
index aec69b0..2366bbd 100644
--- a/content/public/test/android/javatests/src/org/chromium/content/browser/test/util/ApplicationUtils.java
+++ b/content/public/test/android/javatests/src/org/chromium/content/browser/test/util/ApplicationUtils.java
@@ -19,11 +19,10 @@
      * instrumented.
      *
      * @param instrumentation The test instrumentation.
-     * @return Whether the library dependencies were initialized.
      */
-    public static boolean waitForLibraryDependencies(final Instrumentation instrumentation)
+    public static void waitForLibraryDependencies(final Instrumentation instrumentation)
             throws InterruptedException {
-        return CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 Context context = instrumentation.getTargetContext();
diff --git a/content/public/test/android/javatests/src/org/chromium/content/browser/test/util/Criteria.java b/content/public/test/android/javatests/src/org/chromium/content/browser/test/util/Criteria.java
index b7349aac..871441c 100644
--- a/content/public/test/android/javatests/src/org/chromium/content/browser/test/util/Criteria.java
+++ b/content/public/test/android/javatests/src/org/chromium/content/browser/test/util/Criteria.java
@@ -6,12 +6,50 @@
 
 /**
  * Provides a means for validating whether some condition/criteria has been met.
+ * <p>
+ * See {@link CriteriaHelper} for usage guidelines.
  */
-public interface Criteria {
+public abstract class Criteria {
+
+    private String mFailureReason;
+
+    /**
+     * Constructs a Criteria with a default failure message.
+     */
+    public Criteria() {
+        this("Criteria not met in allotted time.");
+    }
+
+    /**
+     * Constructs a Criteria with an explicit message to be shown on failure.
+     * @param failureReason The failure reason to be shown.
+     */
+    public Criteria(String failureReason) {
+        mFailureReason = failureReason;
+    }
 
     /**
      * @return Whether the criteria this is testing has been satisfied.
      */
-    public boolean isSatisfied();
+    public abstract boolean isSatisfied();
+
+    /**
+     * @return The failure message that will be logged if the criteria is not satisfied within
+     *         the specified time range.
+     */
+    public final String getFailureReason() {
+        return mFailureReason;
+    }
+
+    /**
+     * Updates the message to displayed if this criteria does not succeed in the alloted time.  For
+     * correctness, you should be updating this in {@link #isSatisfied()} to ensure the error state
+     * is the same that you last checked.
+     *
+     * @param reason The failure reason to be shown.
+     */
+    public void updateFailureReason(String reason) {
+        mFailureReason = reason;
+    }
 
 }
diff --git a/content/public/test/android/javatests/src/org/chromium/content/browser/test/util/CriteriaHelper.java b/content/public/test/android/javatests/src/org/chromium/content/browser/test/util/CriteriaHelper.java
index 3316c7b..2b08359 100644
--- a/content/public/test/android/javatests/src/org/chromium/content/browser/test/util/CriteriaHelper.java
+++ b/content/public/test/android/javatests/src/org/chromium/content/browser/test/util/CriteriaHelper.java
@@ -8,6 +8,8 @@
 
 import android.os.SystemClock;
 
+import junit.framework.Assert;
+
 import org.chromium.base.ThreadUtils;
 
 import java.util.concurrent.Callable;
@@ -19,6 +21,23 @@
  * If possible, use callbacks or testing delegates instead of criteria as they
  * do not introduce any polling delays.  Should only use Criteria if no suitable
  * other approach exists.
+ *
+ * <p>
+ * <pre>
+ * Sample Usage:
+ * <code>
+ * public void waitForTabTitle(final Tab tab, final String title) {
+ *     CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+ *         {@literal @}Override
+ *         public boolean isSatisified() {
+ *             updateFailureReason("Tab title did not match -- expected: " + title
+ *                     + ", actual: " + tab.getTitle());
+ *             return TextUtils.equals(tab.getTitle(), title);
+ *         }
+ *     });
+ * }
+ * </code>
+ * </pre>
  */
 public class CriteriaHelper {
 
@@ -34,10 +53,9 @@
      * @param maxTimeoutMs The maximum number of ms that this check will be performed for
      * before timeout.
      * @param checkIntervalMs The number of ms between checks.
-     * @return true iff checking has ended with the criteria being satisfied.
      * @throws InterruptedException
      */
-    public static boolean pollForCriteria(Criteria criteria, long maxTimeoutMs,
+    public static void pollForCriteria(Criteria criteria, long maxTimeoutMs,
             long checkIntervalMs) throws InterruptedException {
         boolean isSatisfied = criteria.isSatisfied();
         long startTime = SystemClock.uptimeMillis();
@@ -45,19 +63,18 @@
             Thread.sleep(checkIntervalMs);
             isSatisfied = criteria.isSatisfied();
         }
-        return isSatisfied;
+        Assert.assertTrue(criteria.getFailureReason(), isSatisfied);
     }
 
     /**
      * Checks whether the given Criteria is satisfied polling at a default interval.
      *
      * @param criteria The Criteria that will be checked.
-     * @return iff checking has ended with the criteria being satisfied.
      * @throws InterruptedException
      * @see #pollForCriteria(Criteria, long, long)
      */
-    public static boolean pollForCriteria(Criteria criteria) throws InterruptedException {
-        return pollForCriteria(criteria, DEFAULT_MAX_TIME_TO_POLL, DEFAULT_POLLING_INTERVAL);
+    public static void pollForCriteria(Criteria criteria) throws InterruptedException {
+        pollForCriteria(criteria, DEFAULT_MAX_TIME_TO_POLL, DEFAULT_POLLING_INTERVAL);
     }
 
     /**
@@ -68,11 +85,10 @@
      * @param maxTimeoutMs The maximum number of ms that this check will be performed for
      * before timeout.
      * @param checkIntervalMs The number of ms between checks.
-     * @return iff checking has ended with the criteria being satisfied.
      * @throws InterruptedException
      * @see #pollForCriteria(Criteria)
      */
-    public static boolean pollForUIThreadCriteria(final Criteria criteria, long maxTimeoutMs,
+    public static void pollForUIThreadCriteria(final Criteria criteria, long maxTimeoutMs,
             long checkIntervalMs) throws InterruptedException {
         final Callable<Boolean> callable = new Callable<Boolean>() {
             @Override
@@ -81,7 +97,7 @@
             }
         };
 
-        return pollForCriteria(new Criteria() {
+        pollForCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return ThreadUtils.runOnUiThreadBlockingNoException(callable);
@@ -93,30 +109,11 @@
      * Checks whether the given Criteria is satisfied polling at a default interval on the UI
      * thread.
      * @param criteria The Criteria that will be checked.
-     * @return iff checking has ended with the criteria being satisfied.
      * @throws InterruptedException
      * @see #pollForCriteria(Criteria)
      */
-    public static boolean pollForUIThreadCriteria(final Criteria criteria)
+    public static void pollForUIThreadCriteria(final Criteria criteria)
             throws InterruptedException {
-        return pollForUIThreadCriteria(criteria, DEFAULT_MAX_TIME_TO_POLL,
-                DEFAULT_POLLING_INTERVAL);
-    }
-
-    /**
-     * Performs the runnable action, then checks whether the given criteria are satisfied
-     * until the specified timeout, using the pollForCriteria method. If not, then the runnable
-     * action is performed again, to a maximum of maxAttempts tries.
-     */
-    public static boolean runUntilCriteria(Runnable runnable, Criteria criteria,
-            int maxAttempts, long maxTimeoutMs, long checkIntervalMs) throws InterruptedException {
-        int count = 0;
-        boolean success = false;
-        while (count < maxAttempts && !success) {
-            count++;
-            runnable.run();
-            success = pollForCriteria(criteria, maxTimeoutMs, checkIntervalMs);
-        }
-        return success;
+        pollForUIThreadCriteria(criteria, DEFAULT_MAX_TIME_TO_POLL, DEFAULT_POLLING_INTERVAL);
     }
 }
diff --git a/content/public/test/android/javatests/src/org/chromium/content/browser/test/util/DOMUtils.java b/content/public/test/android/javatests/src/org/chromium/content/browser/test/util/DOMUtils.java
index ebd34a7..53891d7 100644
--- a/content/public/test/android/javatests/src/org/chromium/content/browser/test/util/DOMUtils.java
+++ b/content/public/test/android/javatests/src/org/chromium/content/browser/test/util/DOMUtils.java
@@ -68,11 +68,10 @@
      * Waits until the playback of the media with given {@code id} has started.
      * @param webContents The WebContents in which the media element lives.
      * @param id The element's id to check.
-     * @return Whether the playback has started.
      */
-    public static boolean waitForMediaPlay(final WebContents webContents, final String id)
+    public static void waitForMediaPlay(final WebContents webContents, final String id)
             throws InterruptedException {
-        return CriteriaHelper.pollForCriteria(new Criteria() {
+        CriteriaHelper.pollForCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 try {
@@ -92,11 +91,10 @@
      * Waits until the playback of the media with given {@code id} has stopped.
      * @param webContents The WebContents in which the media element lives.
      * @param id The element's id to check.
-     * @return Whether the playback has paused.
      */
-    public static boolean waitForMediaPause(final WebContents webContents, final String id)
+    public static void waitForMediaPause(final WebContents webContents, final String id)
             throws InterruptedException {
-        return CriteriaHelper.pollForCriteria(new Criteria() {
+        CriteriaHelper.pollForCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 try {
@@ -308,12 +306,11 @@
      * Wait until a given node has non-zero bounds.
      * @param webContents The WebContents in which the node lives.
      * @param nodeId The id of the node.
-     * @return Whether the node started having non-zero bounds.
      */
-    public static boolean waitForNonZeroNodeBounds(final WebContents webContents,
+    public static void waitForNonZeroNodeBounds(final WebContents webContents,
             final String nodeId)
             throws InterruptedException {
-        return CriteriaHelper.pollForCriteria(new Criteria() {
+        CriteriaHelper.pollForCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 try {
diff --git a/content/public/test/android/javatests/src/org/chromium/content/browser/test/util/OrientationChangeObserverCriteria.java b/content/public/test/android/javatests/src/org/chromium/content/browser/test/util/OrientationChangeObserverCriteria.java
index 18ceeebd..9ef5aa84 100644
--- a/content/public/test/android/javatests/src/org/chromium/content/browser/test/util/OrientationChangeObserverCriteria.java
+++ b/content/public/test/android/javatests/src/org/chromium/content/browser/test/util/OrientationChangeObserverCriteria.java
@@ -7,7 +7,7 @@
 /**
  * Criteria used to know when an orientation change happens.
  */
-public class OrientationChangeObserverCriteria implements Criteria {
+public class OrientationChangeObserverCriteria extends Criteria {
 
     private final MockOrientationObserver mObserver;
     private final int mTarget;
diff --git a/content/public/test/browser_test_base.h b/content/public/test/browser_test_base.h
index 781d836..23abda8d 100644
--- a/content/public/test/browser_test_base.h
+++ b/content/public/test/browser_test_base.h
@@ -81,13 +81,6 @@
   // Sets expected browser exit code, in case it's different than 0 (success).
   void set_expected_exit_code(int code) { expected_exit_code_ = code; }
 
-  // Returns the testing server. Guaranteed to be non-NULL.
-  // TODO(phajdan.jr): Remove test_server accessor (http://crbug.com/96594).
-  const net::SpawnedTestServer* test_server() const {
-    return spawned_test_server_.get();
-  }
-  net::SpawnedTestServer* test_server() { return spawned_test_server_.get(); }
-
   const net::SpawnedTestServer* spawned_test_server() const {
     return spawned_test_server_.get();
   }
diff --git a/content/public/test/test_download_request_handler.cc b/content/public/test/test_download_request_handler.cc
new file mode 100644
index 0000000..1c89e0e
--- /dev/null
+++ b/content/public/test/test_download_request_handler.cc
@@ -0,0 +1,671 @@
+// 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.
+
+#include "content/public/test/test_download_request_handler.h"
+
+#include <inttypes.h>
+
+#include "base/logging.h"
+#include "base/memory/weak_ptr.h"
+#include "base/run_loop.h"
+#include "base/sequenced_task_runner.h"
+#include "base/strings/stringprintf.h"
+#include "base/threading/sequenced_task_runner_handle.h"
+#include "content/public/browser/browser_thread.h"
+#include "net/base/io_buffer.h"
+#include "net/http/http_request_headers.h"
+#include "net/http/http_response_headers.h"
+#include "net/url_request/url_request_filter.h"
+#include "net/url_request/url_request_interceptor.h"
+
+namespace content {
+
+// Intercepts URLRequests on behalf of TestDownloadRequestHandler. Necessarily
+// lives on the IO thread since that's where net::URLRequestFilter invokes the
+// URLRequestInterceptor.
+class TestDownloadRequestHandler::Interceptor
+    : public net::URLRequestInterceptor {
+ public:
+  // Invoked on the IO thread to register a URLRequestInterceptor for |url|.
+  // Returns an IO-thread bound weak pointer for interacting with the
+  // interceptor.
+  static base::WeakPtr<Interceptor> Register(
+      const GURL& url,
+      scoped_refptr<base::SequencedTaskRunner> client_task_runner);
+
+  using JobFactory =
+      base::Callback<net::URLRequestJob*(net::URLRequest*,
+                                         net::NetworkDelegate*,
+                                         base::WeakPtr<Interceptor>)>;
+
+  ~Interceptor() override;
+
+  // Unregisters the URLRequestInterceptor. In reality it unregisters whatever
+  // was registered to intercept |url_|. Since |this| is owned by
+  // net::URLRequestFilter, unregistering the interceptor deletes |this| as a
+  // side-effect.
+  void Unregister();
+
+  // Change the URLRequestJob factory. Can be called multiple times.
+  void SetJobFactory(const JobFactory& factory);
+
+  // Sets |requests| to the vector of completed requests and clears the internal
+  // list. The returned requests are stored in the order in which they were
+  // reported as being complete (not necessarily the order in which they were
+  // received).
+  void GetAndResetCompletedRequests(
+      TestDownloadRequestHandler::CompletedRequests* requests);
+
+  // Can be called by a URLRequestJob to notify this interceptor of a completed
+  // request.
+  void AddCompletedRequest(
+      const TestDownloadRequestHandler::CompletedRequest& request);
+
+  // Returns the task runner that should be used for invoking any client
+  // supplied callbacks.
+  scoped_refptr<base::SequencedTaskRunner> GetClientTaskRunner();
+
+ private:
+  Interceptor(const GURL& url,
+              scoped_refptr<base::SequencedTaskRunner> client_task_runner);
+
+  // net::URLRequestInterceptor
+  net::URLRequestJob* MaybeInterceptRequest(
+      net::URLRequest* request,
+      net::NetworkDelegate* network_delegate) const override;
+
+  TestDownloadRequestHandler::CompletedRequests completed_requests_;
+  GURL url_;
+  JobFactory job_factory_;
+  scoped_refptr<base::SequencedTaskRunner> client_task_runner_;
+
+  // mutable because MaybeInterceptRequest() is inexplicably const.
+  mutable base::WeakPtrFactory<Interceptor> weak_ptr_factory_;
+  DISALLOW_COPY_AND_ASSIGN(Interceptor);
+};
+
+// A URLRequestJob that constructs a response to a URLRequest based on the
+// contents of a Parameters object. It can handle partial (i.e. byte range
+// requests). Created on and lives on the IO thread.
+class TestDownloadRequestHandler::PartialResponseJob
+    : public net::URLRequestJob {
+ public:
+  static net::URLRequestJob* Factory(const Parameters& parameters,
+                                     net::URLRequest* request,
+                                     net::NetworkDelegate* delegate,
+                                     base::WeakPtr<Interceptor> interceptor);
+
+  // URLRequestJob
+  void Start() override;
+  void GetResponseInfo(net::HttpResponseInfo* response_info) override;
+  int64 GetTotalReceivedBytes() const override;
+  bool GetMimeType(std::string* mime_type) const override;
+  int GetResponseCode() const override;
+  int ReadRawData(net::IOBuffer* buf, int buf_size) override;
+
+ private:
+  PartialResponseJob(scoped_ptr<Parameters> parameters,
+                     base::WeakPtr<Interceptor> interceptor,
+                     net::URLRequest* url_request,
+                     net::NetworkDelegate* network_delegate);
+
+  ~PartialResponseJob() override;
+  void ReportCompletedRequest(int64_t transferred_byte_count);
+  static void OnStartResponseCallbackOnPossiblyIncorrectThread(
+      base::WeakPtr<PartialResponseJob> job,
+      const std::string& headers,
+      net::Error error);
+  void OnStartResponseCallback(const std::string& headers, net::Error error);
+
+  // In general, the Parameters object can specify an explicit OnStart handler.
+  // In its absence or if the explicit OnStart handler requests the default
+  // behavior, this method can be invoked to respond to the request based on the
+  // remaining Parameters fields (as if there was no OnStart handler).
+  void HandleOnStartDefault();
+
+  // Respond Start() assuming that any If-Match or If-Range headers have been
+  // successfully validated. This handler assumes that there *must* be a Range
+  // header even though the spec doesn't strictly require it for If-Match.
+  bool HandleRangeAssumingValidatorMatch();
+
+  // Adds headers that describe the entity (Content-Type, ETag, Last-Modified).
+  // It also adds an 'Accept-Ranges' header if appropriate.
+  void AddCommonEntityHeaders();
+
+  // Schedules NotifyHeadersComplete() to be called and sets
+  // offset_of_next_read_ to begin reading. Since this interceptor is avoiding
+  // network requests and hence may complete synchronously, it schedules the
+  // NotifyHeadersComplete() call asynchronously in order to avoid unexpected
+  // re-entrancy.
+  void NotifyHeadersCompleteAndPrepareToRead();
+
+  scoped_ptr<Parameters> parameters_;
+
+  base::WeakPtr<Interceptor> interceptor_;
+  net::HttpResponseInfo response_info_;
+  int64_t offset_of_next_read_ = -1;
+  int64_t requested_range_begin_ = -1;
+  int64_t requested_range_end_ = -1;
+  base::WeakPtrFactory<PartialResponseJob> weak_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(PartialResponseJob);
+};
+
+namespace {
+
+template <class T>
+void StoreValueAndInvokeClosure(const base::Closure& closure,
+                                T* value_receiver,
+                                T value) {
+  *value_receiver = value;
+  closure.Run();
+}
+
+// Xorshift* PRNG from https://en.wikipedia.org/wiki/Xorshift
+uint64_t XorShift64StarWithIndex(uint64_t seed, uint64_t index) {
+  const uint64_t kMultiplier = UINT64_C(2685821657736338717);
+  uint64_t x = seed * kMultiplier + index;
+  x ^= x >> 12;
+  x ^= x << 25;
+  x ^= x >> 27;
+  return x * kMultiplier;
+}
+
+void RespondToOnStartedCallbackWithStaticHeaders(
+    const std::string& headers,
+    const net::HttpRequestHeaders&,
+    const TestDownloadRequestHandler::OnStartResponseCallback& callback) {
+  callback.Run(headers, net::OK);
+}
+
+GURL GetNextURLForDownloadInterceptor() {
+  static int index = 0;
+  std::string url_string =
+      base::StringPrintf("https://%d.default.example.com/download/", ++index);
+  return GURL(url_string);
+}
+
+scoped_refptr<net::HttpResponseHeaders> HeadersFromString(
+    const std::string& headers_string) {
+  scoped_refptr<net::HttpResponseHeaders> headers =
+      new net::HttpResponseHeaders(net::HttpUtil::AssembleRawHeaders(
+          headers_string.c_str(), headers_string.size()));
+  return headers;
+}
+
+}  // namespace
+
+// static
+net::URLRequestJob* TestDownloadRequestHandler::PartialResponseJob::Factory(
+    const Parameters& parameters,
+    net::URLRequest* request,
+    net::NetworkDelegate* delegate,
+    base::WeakPtr<Interceptor> interceptor) {
+  return new PartialResponseJob(make_scoped_ptr(new Parameters(parameters)),
+                                interceptor, request, delegate);
+}
+
+TestDownloadRequestHandler::PartialResponseJob::PartialResponseJob(
+    scoped_ptr<Parameters> parameters,
+    base::WeakPtr<Interceptor> interceptor,
+    net::URLRequest* request,
+    net::NetworkDelegate* network_delegate)
+    : net::URLRequestJob(request, network_delegate),
+      parameters_(parameters.Pass()),
+      interceptor_(interceptor),
+      weak_factory_(this) {
+  DCHECK(parameters_.get());
+  DCHECK_LT(0, parameters_->size);
+  DCHECK_NE(-1, parameters_->pattern_generator_seed);
+}
+
+TestDownloadRequestHandler::PartialResponseJob::~PartialResponseJob() {}
+
+void TestDownloadRequestHandler::PartialResponseJob::Start() {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DVLOG(1) << "Starting request for " << request()->url().spec();
+
+  if (parameters_->on_start_handler.is_null() || !interceptor_.get()) {
+    HandleOnStartDefault();
+    return;
+  }
+
+  DVLOG(1) << "Invoking custom OnStart handler.";
+  interceptor_->GetClientTaskRunner()->PostTask(
+      FROM_HERE,
+      base::Bind(
+          parameters_->on_start_handler, request()->extra_request_headers(),
+          base::Bind(&PartialResponseJob::
+                         OnStartResponseCallbackOnPossiblyIncorrectThread,
+                     weak_factory_.GetWeakPtr())));
+}
+
+void TestDownloadRequestHandler::PartialResponseJob::GetResponseInfo(
+    net::HttpResponseInfo* response_info) {
+  *response_info = response_info_;
+}
+
+int64 TestDownloadRequestHandler::PartialResponseJob::GetTotalReceivedBytes()
+    const {
+  return offset_of_next_read_ - requested_range_begin_;
+}
+
+bool TestDownloadRequestHandler::PartialResponseJob::GetMimeType(
+    std::string* mime_type) const {
+  *mime_type = parameters_->content_type;
+  return !parameters_->content_type.empty();
+}
+
+int TestDownloadRequestHandler::PartialResponseJob::GetResponseCode() const {
+  return response_info_.headers.get() ? response_info_.headers->response_code()
+                                      : 0;
+}
+
+int TestDownloadRequestHandler::PartialResponseJob::ReadRawData(
+    net::IOBuffer* buf,
+    int buf_size) {
+  DVLOG(1) << "Preparing to read " << buf_size << " bytes";
+
+  // requested_range_begin_ == -1 implies that the body was empty.
+  if (offset_of_next_read_ > requested_range_end_ ||
+      requested_range_begin_ == -1) {
+    ReportCompletedRequest(requested_range_end_ - requested_range_begin_ + 1);
+    DVLOG(1) << "Done reading.";
+    return 0;
+  }
+
+  int64_t range_end =
+      std::min(requested_range_end_, offset_of_next_read_ + buf_size - 1);
+
+  if (!parameters_->injected_errors.empty()) {
+    const InjectedError& injected_error = parameters_->injected_errors.front();
+
+    if (offset_of_next_read_ == injected_error.offset) {
+      int error = injected_error.error;
+      SetStatus(net::URLRequestStatus(net::URLRequestStatus::FAILED, error));
+      DVLOG(1) << "Returning error " << net::ErrorToString(error);
+      ReportCompletedRequest(injected_error.offset - requested_range_begin_);
+      parameters_->injected_errors.pop();
+      return error;
+    }
+
+    if (offset_of_next_read_ < injected_error.offset &&
+        injected_error.offset <= range_end)
+      range_end = injected_error.offset - 1;
+  }
+  int bytes_to_copy = (range_end - offset_of_next_read_) + 1;
+
+  TestDownloadRequestHandler::GetPatternBytes(
+      parameters_->pattern_generator_seed, offset_of_next_read_, bytes_to_copy,
+      buf->data());
+  DVLOG(1) << "Read " << bytes_to_copy << " bytes at offset "
+           << offset_of_next_read_;
+  offset_of_next_read_ += bytes_to_copy;
+  return bytes_to_copy;
+}
+
+void TestDownloadRequestHandler::PartialResponseJob::ReportCompletedRequest(
+    int64_t transferred_byte_count) {
+  if (interceptor_.get()) {
+    TestDownloadRequestHandler::CompletedRequest completed_request;
+    completed_request.transferred_byte_count = transferred_byte_count;
+    completed_request.request_headers = request()->extra_request_headers();
+    interceptor_->AddCompletedRequest(completed_request);
+  }
+}
+
+// static
+void TestDownloadRequestHandler::PartialResponseJob::
+    OnStartResponseCallbackOnPossiblyIncorrectThread(
+        base::WeakPtr<PartialResponseJob> job,
+        const std::string& headers,
+        net::Error error) {
+  BrowserThread::PostTask(
+      BrowserThread::IO, FROM_HERE,
+      base::Bind(&PartialResponseJob::OnStartResponseCallback, job, headers,
+                 error));
+}
+
+void TestDownloadRequestHandler::PartialResponseJob::OnStartResponseCallback(
+    const std::string& headers,
+    net::Error error) {
+  DVLOG(1) << "OnStartResponse invoked with error:" << error
+           << " and headers:" << std::endl
+           << headers;
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  if (headers.empty() && error == net::OK) {
+    HandleOnStartDefault();
+    return;
+  }
+
+  if (error != net::OK) {
+    NotifyStartError(net::URLRequestStatus::FromError(error));
+    return;
+  }
+
+  response_info_.headers = new net::HttpResponseHeaders(
+      net::HttpUtil::AssembleRawHeaders(headers.c_str(), headers.size()));
+  NotifyHeadersCompleteAndPrepareToRead();
+}
+
+void TestDownloadRequestHandler::PartialResponseJob::HandleOnStartDefault() {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  SetStatus(net::URLRequestStatus());
+
+  const net::HttpRequestHeaders& extra_headers =
+      request()->extra_request_headers();
+
+  DCHECK(request()->method() == "GET") << "PartialResponseJob only "
+                                          "knows how to respond to GET "
+                                          "requests";
+  std::string value;
+
+  // If the request contains an 'If-Range' header and the value matches our
+  // ETag, then try to handle the range request.
+  if (parameters_->support_byte_ranges &&
+      extra_headers.GetHeader(net::HttpRequestHeaders::kIfRange, &value) &&
+      value == parameters_->etag && HandleRangeAssumingValidatorMatch())
+    return;
+
+  if (parameters_->support_byte_ranges &&
+      extra_headers.GetHeader("If-Match", &value)) {
+    if (value == parameters_->etag && HandleRangeAssumingValidatorMatch())
+      return;
+
+    // Unlike If-Range, If-Match returns an error if the validators don't match.
+    response_info_.headers = HeadersFromString(
+        "HTTP/1.1 412 Precondition failed\r\n"
+        "Content-Length: 0\r\n");
+    requested_range_begin_ = requested_range_end_ = -1;
+    NotifyHeadersCompleteAndPrepareToRead();
+    return;
+  }
+
+  requested_range_begin_ = 0;
+  requested_range_end_ = parameters_->size - 1;
+  response_info_.headers =
+      HeadersFromString(base::StringPrintf("HTTP/1.1 200 Success\r\n"
+                                           "Content-Length: %" PRId64 "\r\n",
+                                           parameters_->size));
+  AddCommonEntityHeaders();
+  NotifyHeadersCompleteAndPrepareToRead();
+  return;
+}
+
+bool TestDownloadRequestHandler::PartialResponseJob::
+    HandleRangeAssumingValidatorMatch() {
+  const net::HttpRequestHeaders& extra_headers =
+      request()->extra_request_headers();
+
+  std::string range_header;
+  std::vector<net::HttpByteRange> byte_ranges;
+
+  // There needs to be a 'Range' header and it should have exactly one range.
+  // This server is not going to deal with multiple ranges.
+  if (!extra_headers.GetHeader(net::HttpRequestHeaders::kRange,
+                               &range_header) ||
+      !net::HttpUtil::ParseRangeHeader(range_header, &byte_ranges) ||
+      byte_ranges.size() != 1)
+    return false;
+
+  // The request may have specified a range that's out of bounds.
+  if (!byte_ranges[0].ComputeBounds(parameters_->size)) {
+    response_info_.headers = HeadersFromString(
+        base::StringPrintf("HTTP/1.1 416 Range not satisfiable\r\n"
+                           "Content-Range: bytes */%" PRId64 "\r\n"
+                           "Content-Length: 0\r\n",
+                           parameters_->size));
+    requested_range_begin_ = requested_range_end_ = -1;
+    NotifyHeadersCompleteAndPrepareToRead();
+    return true;
+  }
+
+  requested_range_begin_ = byte_ranges[0].first_byte_position();
+  requested_range_end_ = byte_ranges[0].last_byte_position();
+  response_info_.headers =
+      HeadersFromString(base::StringPrintf(
+          "HTTP/1.1 206 Partial content\r\n"
+          "Content-Range: bytes %" PRId64 "-%" PRId64 "/%" PRId64 "\r\n"
+          "Content-Length: %" PRId64 "\r\n",
+          requested_range_begin_, requested_range_end_, parameters_->size,
+          (requested_range_end_ - requested_range_begin_) + 1));
+  AddCommonEntityHeaders();
+  NotifyHeadersCompleteAndPrepareToRead();
+  return true;
+}
+
+void TestDownloadRequestHandler::PartialResponseJob::AddCommonEntityHeaders() {
+  if (parameters_->support_byte_ranges)
+    response_info_.headers->AddHeader("Accept-Ranges: bytes");
+
+  if (!parameters_->content_type.empty())
+    response_info_.headers->AddHeader(base::StringPrintf(
+        "Content-Type: %s", parameters_->content_type.c_str()));
+
+  if (!parameters_->etag.empty())
+    response_info_.headers->AddHeader(
+        base::StringPrintf("ETag: %s", parameters_->etag.c_str()));
+
+  if (!parameters_->last_modified.empty())
+    response_info_.headers->AddHeader(base::StringPrintf(
+        "Last-Modified: %s", parameters_->last_modified.c_str()));
+}
+
+void TestDownloadRequestHandler::PartialResponseJob::
+    NotifyHeadersCompleteAndPrepareToRead() {
+  std::string normalized_headers;
+  response_info_.headers->GetNormalizedHeaders(&normalized_headers);
+  DVLOG(1) << "Notify ready with headers:\n" << normalized_headers;
+
+  offset_of_next_read_ = requested_range_begin_;
+
+  // Flush out injected_errors that no longer apply. We are going to skip over
+  // ones where the |offset| == |requested_range_begin_| as well. While it
+  // prevents injecting an error at offset 0, it makes it much easier to set up
+  // parameter sets for download resumption. It means that when a request is
+  // interrupted at offset O, a subsequent request for the range O-<end> won't
+  // immediately interrupt as well. If we don't exclude interruptions at
+  // relative offset 0, then test writers would need to reset the parameter
+  // prior to each resumption rather than once at the beginning of the test.
+  while (!parameters_->injected_errors.empty() &&
+         parameters_->injected_errors.front().offset <= requested_range_begin_)
+    parameters_->injected_errors.pop();
+
+  base::MessageLoop::current()->PostTask(
+      FROM_HERE, base::Bind(&PartialResponseJob::NotifyHeadersComplete,
+                            weak_factory_.GetWeakPtr()));
+}
+
+// static
+base::WeakPtr<TestDownloadRequestHandler::Interceptor>
+TestDownloadRequestHandler::Interceptor::Register(
+    const GURL& url,
+    scoped_refptr<base::SequencedTaskRunner> client_task_runner) {
+  DCHECK(url.is_valid());
+  scoped_ptr<Interceptor> interceptor(new Interceptor(url, client_task_runner));
+  base::WeakPtr<Interceptor> weak_reference =
+      interceptor->weak_ptr_factory_.GetWeakPtr();
+  net::URLRequestFilter* filter = net::URLRequestFilter::GetInstance();
+  filter->AddUrlInterceptor(url, interceptor.Pass());
+  return weak_reference;
+}
+
+void TestDownloadRequestHandler::Interceptor::Unregister() {
+  net::URLRequestFilter* filter = net::URLRequestFilter::GetInstance();
+  filter->RemoveUrlHandler(url_);
+  // We are deleted now since the filter owned |this|.
+}
+
+void TestDownloadRequestHandler::Interceptor::SetJobFactory(
+    const JobFactory& job_factory) {
+  job_factory_ = job_factory;
+}
+
+void TestDownloadRequestHandler::Interceptor::GetAndResetCompletedRequests(
+    TestDownloadRequestHandler::CompletedRequests* requests) {
+  requests->clear();
+  completed_requests_.swap(*requests);
+}
+
+void TestDownloadRequestHandler::Interceptor::AddCompletedRequest(
+    const TestDownloadRequestHandler::CompletedRequest& request) {
+  completed_requests_.push_back(request);
+}
+
+scoped_refptr<base::SequencedTaskRunner>
+TestDownloadRequestHandler::Interceptor::GetClientTaskRunner() {
+  return client_task_runner_;
+}
+
+TestDownloadRequestHandler::Interceptor::Interceptor(
+    const GURL& url,
+    scoped_refptr<base::SequencedTaskRunner> client_task_runner)
+    : url_(url),
+      client_task_runner_(client_task_runner),
+      weak_ptr_factory_(this) {}
+
+TestDownloadRequestHandler::Interceptor::~Interceptor() {}
+
+net::URLRequestJob*
+TestDownloadRequestHandler::Interceptor::MaybeInterceptRequest(
+    net::URLRequest* request,
+    net::NetworkDelegate* network_delegate) const {
+  DVLOG(1) << "Intercepting request for " << request->url()
+           << " with headers:\n" << request->extra_request_headers().ToString();
+  if (job_factory_.is_null())
+    return nullptr;
+  return job_factory_.Run(request, network_delegate,
+                          weak_ptr_factory_.GetWeakPtr());
+}
+
+TestDownloadRequestHandler::InjectedError::InjectedError(int64_t offset,
+                                                         net::Error error)
+    : offset(offset), error(error) {}
+
+// static
+TestDownloadRequestHandler::Parameters
+TestDownloadRequestHandler::Parameters::WithSingleInterruption() {
+  Parameters parameters;
+  parameters.injected_errors.push(
+      InjectedError(parameters.size / 2, net::ERR_CONNECTION_RESET));
+  return parameters;
+}
+
+TestDownloadRequestHandler::Parameters::Parameters()
+    : etag("abcd"),
+      last_modified("Tue, 15 Nov 1994 12:45:26 GMT"),
+      content_type("application/octet-stream"),
+      size(102400),
+      pattern_generator_seed(1),
+      support_byte_ranges(true) {}
+
+// Copy and move constructors / assignment operators are all defaults.
+TestDownloadRequestHandler::Parameters::Parameters(const Parameters&) = default;
+TestDownloadRequestHandler::Parameters& TestDownloadRequestHandler::Parameters::
+operator=(const Parameters&) = default;
+
+TestDownloadRequestHandler::Parameters::Parameters(Parameters&& that)
+    : etag(std::move(that.etag)),
+      last_modified(std::move(that.last_modified)),
+      content_type(std::move(that.content_type)),
+      size(that.size),
+      pattern_generator_seed(that.pattern_generator_seed),
+      on_start_handler(that.on_start_handler),
+      injected_errors(std::move(that.injected_errors)) {}
+
+TestDownloadRequestHandler::Parameters& TestDownloadRequestHandler::Parameters::
+operator=(Parameters&& that) {
+  etag = std::move(that.etag);
+  last_modified = std::move(that.etag);
+  content_type = std::move(that.content_type);
+  size = that.size;
+  pattern_generator_seed = that.pattern_generator_seed;
+  on_start_handler = that.on_start_handler;
+  injected_errors.swap(that.injected_errors);
+  return *this;
+}
+
+TestDownloadRequestHandler::Parameters::~Parameters() {}
+
+void TestDownloadRequestHandler::Parameters::ClearInjectedErrors() {
+  std::queue<InjectedError> empty_error_list;
+  injected_errors.swap(empty_error_list);
+}
+
+TestDownloadRequestHandler::TestDownloadRequestHandler()
+    : TestDownloadRequestHandler(GetNextURLForDownloadInterceptor()) {}
+
+TestDownloadRequestHandler::TestDownloadRequestHandler(const GURL& url)
+    : url_(url) {
+  DCHECK(base::SequencedTaskRunnerHandle::IsSet());
+  base::RunLoop run_loop;
+  BrowserThread::PostTaskAndReplyWithResult(
+      BrowserThread::IO, FROM_HERE,
+      base::Bind(&Interceptor::Register, url_,
+                 base::SequencedTaskRunnerHandle::Get()),
+      base::Bind(&StoreValueAndInvokeClosure<base::WeakPtr<Interceptor>>,
+                 run_loop.QuitClosure(), &interceptor_));
+  run_loop.Run();
+}
+
+void TestDownloadRequestHandler::StartServing(const Parameters& parameters) {
+  DCHECK(CalledOnValidThread());
+  Interceptor::JobFactory job_factory =
+      base::Bind(&PartialResponseJob::Factory, parameters);
+  // Interceptor, if valid, is already registered and serving requests. We just
+  // need to set the correct job factory for it to start serving using the new
+  // parameters.
+  BrowserThread::PostTask(
+      BrowserThread::IO, FROM_HERE,
+      base::Bind(&Interceptor::SetJobFactory, interceptor_, job_factory));
+}
+
+void TestDownloadRequestHandler::StartServingStaticResponse(
+    const base::StringPiece& headers) {
+  DCHECK(CalledOnValidThread());
+  Parameters parameters;
+  parameters.on_start_handler = base::Bind(
+      &RespondToOnStartedCallbackWithStaticHeaders, headers.as_string());
+  StartServing(parameters);
+}
+
+// static
+void TestDownloadRequestHandler::GetPatternBytes(int seed,
+                                                 int64_t starting_offset,
+                                                 int length,
+                                                 char* buffer) {
+  int64_t seed_offset = starting_offset / sizeof(int64_t);
+  int64_t first_byte_position = starting_offset % sizeof(int64_t);
+  while (length > 0) {
+    uint64_t data = XorShift64StarWithIndex(seed, seed_offset);
+    int length_to_copy =
+        std::min(length, static_cast<int>(sizeof(data) - first_byte_position));
+    memcpy(buffer, reinterpret_cast<char*>(&data) + first_byte_position,
+           length_to_copy);
+    buffer += length_to_copy;
+    length -= length_to_copy;
+    ++seed_offset;
+    first_byte_position = 0;
+  }
+}
+
+TestDownloadRequestHandler::~TestDownloadRequestHandler() {
+  DCHECK(CalledOnValidThread());
+  BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
+                          base::Bind(&Interceptor::Unregister, interceptor_));
+}
+
+void TestDownloadRequestHandler::GetCompletedRequestInfo(
+    TestDownloadRequestHandler::CompletedRequests* requests) {
+  DCHECK(CalledOnValidThread());
+  base::RunLoop run_loop;
+  BrowserThread::PostTaskAndReply(
+      BrowserThread::IO, FROM_HERE,
+      base::Bind(&Interceptor::GetAndResetCompletedRequests, interceptor_,
+                 requests),
+      run_loop.QuitClosure());
+  run_loop.Run();
+}
+
+}  // namespace content
diff --git a/content/public/test/test_download_request_handler.h b/content/public/test/test_download_request_handler.h
new file mode 100644
index 0000000..19209a2
--- /dev/null
+++ b/content/public/test/test_download_request_handler.h
@@ -0,0 +1,306 @@
+// 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.
+
+#ifndef CONTENT_PUBLIC_TEST_TEST_DOWNLOAD_REQUEST_HANDLER_H_
+#define CONTENT_PUBLIC_TEST_TEST_DOWNLOAD_REQUEST_HANDLER_H_
+
+#include <stdint.h>
+#include <queue>
+
+#include "base/callback_forward.h"
+#include "base/files/file.h"
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "base/threading/non_thread_safe.h"
+#include "net/base/completion_callback.h"
+#include "net/base/net_errors.h"
+#include "net/http/http_byte_range.h"
+#include "net/http/http_response_headers.h"
+#include "net/http/http_util.h"
+#include "net/url_request/url_request_job.h"
+#include "url/gurl.h"
+
+namespace content {
+
+// A request handler that can be used to mock the behavior of a URLRequestJob
+// for a download.
+//
+// Testing of download interruption scenarios typically involve simulating
+// errors that occur:
+// 1. On the client, prior to the request being sent out,
+// 2. On the network, between the client and the server,
+// 3. On the server,
+// 4. Back on the client, while writing the response to disk,
+// 5. On the client, after the response has been written to disk.
+//
+// This test class is meant to help test failures in #2 and #3 above. The test
+// implementation depends on content::BrowserThread and assumes that the
+// thread identified by BrowserThread::IO is the network task runner thread.
+//
+// TestDownloadRequestHandler can be used on any thread as long as it is used
+// and destroyed on the same thread it was constructed on.
+//
+// To use the test request handler:
+//
+//  // Define the request handler. Note that initialization of the
+//  // TestDownloadRequestHandler object immediately registers it as well and is
+//  // a blocking operation.
+//  TestDownloadRequestHandler request_handler;
+//
+//  // Set up parameters for the partial request handler.
+//  TestDownloadRequestHandler::Parameters parameters;
+//
+//  // Inject an error at offset 100.
+//  parameters.injected_errors.push(TestDownloadRequestHandler::InjectedError(
+//      100, net::ERR_CONNECTION_RESET));
+//
+//  // Start serving.
+//  request_handler.StartServing(parameters);
+//
+// At this point, you can initiate a URLRequest for request_handler.url(). The
+// request will fail when offset 100 is reached with the error specified above.
+class TestDownloadRequestHandler : public base::NonThreadSafe {
+ public:
+  // OnStartHandler can be used to intercept the Start() event of a new
+  // URLRequest. Set it as the |on_start_handler| member of Parameters below.
+  //
+  // The callback is invoked on the thread on which TestDownloadRequestHandler
+  // was created. Once the callback has a response ready, it can invoke the
+  // OnStartResponseCallback object. The latter can be invoked on any thread and
+  // will post back to the IO thread to continue with processing the Start()
+  // event.
+  //
+  // The parameters to the OnStartResponseCallback are:
+  //
+  // * a |const std::string&| containing the headers to be sent in response to
+  //   the request. The headers should be formatted according to the
+  //   requirements of net::HttpUtil::AssembleRawHeaders(). The headers are only
+  //   used if the |net::Error| parameters is net::OK.
+  //
+  // * a |net::Error| indicating the result of the operation. If this parameters
+  //   is not net::OK, then that error value is set as the result of the Start()
+  //   operation. The headers are ignored in this case.
+  //
+  //   If the error is net::OK, and the headers are empty, then the request is
+  //   handled based on the remaining parameters in |Parameters|.
+  using OnStartResponseCallback =
+      base::Callback<void(const std::string&, net::Error)>;
+
+  using OnStartHandler = base::Callback<void(const net::HttpRequestHeaders&,
+                                             const OnStartResponseCallback&)>;
+
+  // An injected error.
+  struct InjectedError {
+    InjectedError(int64_t offset, net::Error error);
+
+    int64_t offset;
+    net::Error error;
+  };
+
+  // Parameters used by StartServing().
+  struct Parameters {
+    // Constructs a Parameters structure using the default constructor, but with
+    // the addition of a net::ERR_CONNECTION_RESET which will be triggered at
+    // byte offset (filesize / 2).
+    static Parameters WithSingleInterruption();
+
+    // The default constructor initializes the parameters for serving a 100 KB
+    // resource with no interruptions. The response contains an ETag and a
+    // Last-Modified header and the server supports byte range requests.
+    Parameters();
+
+    // Parameters is expected to be copyable and moveable.
+    Parameters(Parameters&&);
+    Parameters(const Parameters&);
+    Parameters& operator=(Parameters&&);
+    Parameters& operator=(const Parameters&);
+    ~Parameters();
+
+    // Clears the errors in injected_errors.
+    void ClearInjectedErrors();
+
+    // Contents of the ETag header field of the response.  No Etag header is
+    // sent if this field is empty.
+    std::string etag;
+
+    // Contents of the Last-Modified header field of the response. No
+    // Last-Modified header is sent if this field is empty.
+    std::string last_modified;
+
+    // The Content-Type of the response. No Content-Type header is sent if this
+    // field is empty.
+    std::string content_type;
+
+    // The total size of the entity. If the entire entity is requested, then
+    // this would be the same as the value returned in the Content-Length
+    // header.
+    int64_t size;
+
+    // Seed for the pseudo-random sequence that defines the response body
+    // contents. The seed is with GetPatternBytes() to generate the body of the
+    // response.
+    int pattern_generator_seed;
+
+    // If true, the response contains a 'Accept-Ranges: bytes' header.
+    bool support_byte_ranges;
+
+    // If on_start_handler is valid, it will be invoked when a new request is
+    // received. See details about the OnStartHandler above.
+    OnStartHandler on_start_handler;
+
+    // Errors to be injected. Each injected error is defined by an offset and an
+    // error. Request handler will successfully fulfil requests to read up to
+    // |offset|. An attempt to read the byte at |offset| will result in the
+    // error defined by the InjectErrors object.
+    //
+    // If a read spans the range containing |offset|, then the portion of the
+    // request preceding |offset| will succeed. The next read would start at
+    // |offset| and hence would result in an error.
+    //
+    // E.g.: injected_errors.push(InjectedError(100, ERR_CONNECTION_RESET));
+    //
+    //    A network read for 1024 bytes at offset 0 would result in successfully
+    //    reading 100 bytes (bytes with offset 0-99). The next read would,
+    //    therefore, start at offset 100 and would result in
+    //    ERR_CONNECTION_RESET.
+    //
+    // Injected errors are processed in the order in which they appear in
+    // |injected_errors|. When handling a network request for the range [S,E]
+    // (inclusive), all events in |injected_errors| where |offset| is less than
+    // S will be ignored. The first event remaining will trigger an error once
+    // the sequence of reads proceeds to a point where its |offset| is included
+    // in [S,E].
+    //
+    // This implies that |injected_errors| must be specified in increasing order
+    // of |offset|. I.e. |injected_errors| must be sorted by |offset|.
+    //
+    // Errors at relative offset 0 are ignored for a partial request. I.e. If
+    // the request is for the byte range 100-200, then an error at offset 100
+    // will not trigger. This is done so that non-overlapping continuation
+    // attempts don't require resetting parameters to succeed.
+    //
+    // E.g.: If the caller injects an error at offset 100, then a request for
+    // the entire entity will fail after reading 100 bytes (offsets 0 through
+    // 99). A subsequent request for byte range "100-" (offsets 100 through EOF)
+    // will succeed since the error at offset 100 is ignored.
+    //
+    // Notes:
+    //
+    // * Distinctions about which read requests signal the error is often only
+    //   important at the //net layer. From //content, it would appear that 100
+    //   bytes were read and then request failed with ERR_CONNECTION_RESET.
+    std::queue<InjectedError> injected_errors;
+  };
+
+  // Details about completed requests returned by GetCompletedRequestInfo().
+  struct CompletedRequest {
+    // Count of bytes read by the client of the URLRequestJob. This counts the
+    // number of bytes of the entity that was transferred *after* content
+    // decoding is complete.
+    int64_t transferred_byte_count = -1;
+
+    net::HttpRequestHeaders request_headers;
+  };
+
+  using CompletedRequests = std::vector<CompletedRequest>;
+
+  // Registers a request handler at the default URL. Call url() to determine the
+  // URL.
+  //
+  // Notes:
+  // * This constructor is only meant to be used for convenience when the caller
+  //   is not interested in the URL used for interception. The URL used is
+  //   generated at run time and should not be assumed to be the same across
+  //   different runs of the same test.
+  //
+  // * Initialization of the handler synchronously runs a task on the
+  //   BrowserThread::IO thread using a nested message loop. Only construct an
+  //   instance of this object after browser threads have been initialized.
+  TestDownloadRequestHandler();
+
+  // Similar to the default constructor, but registers the handler at |url|.
+  //
+  // Notes:
+  // * The behavior is undefined if more than one TestDownloadRequestHandler is
+  //   registered for the same URL.
+  TestDownloadRequestHandler(const GURL& url);
+
+  // Destroys and posts a task to the IO thread to dismantle the registered URL
+  // request interceptor. Does not wait for the task to return.
+  ~TestDownloadRequestHandler();
+
+  // Returns the URL that this instance is intercepting URLRequests for.
+  const GURL& url() const { return url_; }
+
+  // Start responding to URLRequests for url() with responses based on
+  // |parameters|.
+  //
+  // This method invocation posts a task to the IO thread to update the
+  // URLRequestInterceptor with the new parameters and returns immediately. URL
+  // interception won't be updated until the posted task executes. The method
+  // returns without waiting for the posted task to complete.
+  //
+  // Calling this method does not affect URLRequests that have already started.
+  // The new parameters will only be used to respond to new URLRequests that are
+  // starting.
+  //
+  // StartServing() can be called multiple times to change the operating
+  // parameters of the current URL interceptor.
+  void StartServing(const Parameters& parameters);
+
+  // Start responding to URLRequests for url() with a static response
+  // containing the headers in |headers|.
+  //
+  // The format of |headers| should comply with the requirements for
+  // net::HttpUtil::AssembleRawHeaders().
+  void StartServingStaticResponse(const base::StringPiece& headers);
+
+  // Get the list of requests that have already completed.
+  //
+  // This method posts a task to the IO thread to collect the list of completed
+  // requests and waits for the task to complete.
+  //
+  // Requests that are currently in progress will not be reflected in
+  // |requests|.
+  void GetCompletedRequestInfo(CompletedRequests* requests);
+
+  // Generate a pseudo random pattern.
+  //
+  // |seed| is the seed for the pseudo random sequence.  |offset| is the byte
+  // offset into the sequence.  |length| is a count of bytes to generate.
+  // |data| receives the generated bytes and should be able to store |length|
+  // bytes.
+  //
+  // The pattern has the following properties:
+  //
+  // * For a given |seed|, the entire sequence of bytes is fixed. Any
+  //   subsequence can be generated by specifying the |offset| and |length|.
+  //
+  // * The sequence is aperiodic (at least for the first 1M bytes).
+  //
+  // * |seed| is chaotic. Different seeds produce "very different" data. This
+  //   means that there's no trivial mapping between sequences generated using
+  //   two distinct seeds.
+  //
+  // These properties make the generated bytes useful for testing partial
+  // requests where the response may need to be built using a sequence of
+  // partial requests.
+  //
+  // Note: Don't use this function to generate a cryptographically secure
+  // pseudo-random sequence.
+  static void GetPatternBytes(int seed, int64 offset, int length, char* data);
+
+ private:
+  class Interceptor;
+  class PartialResponseJob;
+
+  GURL url_;
+  base::WeakPtr<Interceptor> interceptor_;
+  DISALLOW_COPY_AND_ASSIGN(TestDownloadRequestHandler);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_PUBLIC_TEST_TEST_DOWNLOAD_REQUEST_HANDLER_H_
diff --git a/content/renderer/BUILD.gn b/content/renderer/BUILD.gn
index bf1d4de..f009eeed 100644
--- a/content/renderer/BUILD.gn
+++ b/content/renderer/BUILD.gn
@@ -77,12 +77,7 @@
   ]
 
   if (use_aura) {
-    sources += [
-      "render_widget_mus_connection.cc",
-      "render_widget_mus_connection.h",
-      "render_widget_window_tree_client_factory.cc",
-      "render_widget_window_tree_client_factory.h",
-    ]
+    deps += [ "//content/renderer/mus" ]
   }
 
   if (is_mac) {
diff --git a/content/renderer/browser_plugin/browser_plugin.cc b/content/renderer/browser_plugin/browser_plugin.cc
index 7dc2756..0af3aa46 100644
--- a/content/renderer/browser_plugin/browser_plugin.cc
+++ b/content/renderer/browser_plugin/browser_plugin.cc
@@ -561,16 +561,6 @@
 void BrowserPlugin::didFailLoading(const blink::WebURLError& error) {
 }
 
-void BrowserPlugin::didFinishLoadingFrameRequest(const blink::WebURL& url,
-                                                 void* notify_data) {
-}
-
-void BrowserPlugin::didFailLoadingFrameRequest(
-    const blink::WebURL& url,
-    void* notify_data,
-    const blink::WebURLError& error) {
-}
-
 bool BrowserPlugin::executeEditCommand(const blink::WebString& name) {
   BrowserPluginManager::Get()->Send(new BrowserPluginHostMsg_ExecuteEditCommand(
       browser_plugin_instance_id_,
diff --git a/content/renderer/browser_plugin/browser_plugin.h b/content/renderer/browser_plugin/browser_plugin.h
index 70a61ee..5069e87b 100644
--- a/content/renderer/browser_plugin/browser_plugin.h
+++ b/content/renderer/browser_plugin/browser_plugin.h
@@ -109,11 +109,6 @@
   void didReceiveData(const char* data, int data_length) override;
   void didFinishLoading() override;
   void didFailLoading(const blink::WebURLError& error) override;
-  void didFinishLoadingFrameRequest(const blink::WebURL& url,
-                                    void* notify_data) override;
-  void didFailLoadingFrameRequest(const blink::WebURL& url,
-                                  void* notify_data,
-                                  const blink::WebURLError& error) override;
   bool executeEditCommand(const blink::WebString& name) override;
   bool executeEditCommand(const blink::WebString& name,
                           const blink::WebString& value) override;
diff --git a/content/renderer/media/cdm/ppapi_decryptor.cc b/content/renderer/media/cdm/ppapi_decryptor.cc
index a4b51bb..023c361 100644
--- a/content/renderer/media/cdm/ppapi_decryptor.cc
+++ b/content/renderer/media/cdm/ppapi_decryptor.cc
@@ -161,6 +161,7 @@
     const std::string& session_id,
     const std::vector<uint8_t>& response,
     scoped_ptr<media::SimpleCdmPromise> promise) {
+  DVLOG(2) << __FUNCTION__;
   DCHECK(render_task_runner_->BelongsToCurrentThread());
 
   if (!CdmDelegate()) {
@@ -172,6 +173,7 @@
 
 void PpapiDecryptor::CloseSession(const std::string& session_id,
                                   scoped_ptr<media::SimpleCdmPromise> promise) {
+  DVLOG(2) << __FUNCTION__;
   DCHECK(render_task_runner_->BelongsToCurrentThread());
 
   if (!CdmDelegate()) {
@@ -185,6 +187,7 @@
 void PpapiDecryptor::RemoveSession(
     const std::string& session_id,
     scoped_ptr<media::SimpleCdmPromise> promise) {
+  DVLOG(2) << __FUNCTION__;
   DCHECK(render_task_runner_->BelongsToCurrentThread());
 
   if (!CdmDelegate()) {
@@ -401,6 +404,7 @@
 void PpapiDecryptor::OnSessionKeysChange(const std::string& session_id,
                                          bool has_additional_usable_key,
                                          media::CdmKeysInfo keys_info) {
+  DVLOG(2) << __FUNCTION__ << ": " << has_additional_usable_key;
   DCHECK(render_task_runner_->BelongsToCurrentThread());
 
   // TODO(jrummell): Handling resume playback should be done in the media
diff --git a/content/renderer/media/rtc_video_decoder.cc b/content/renderer/media/rtc_video_decoder.cc
index aebe9f28..1f43ba24 100644
--- a/content/renderer/media/rtc_video_decoder.cc
+++ b/content/renderer/media/rtc_video_decoder.cc
@@ -674,7 +674,9 @@
     DVLOG(1) << "Unsupported profile " << profile;
   } else {
     vda_ = factories_->CreateVideoDecodeAccelerator();
-    if (vda_ && !vda_->Initialize(profile, this))
+
+    media::VideoDecodeAccelerator::Config config(profile);
+    if (vda_ && !vda_->Initialize(config, this))
       vda_.release()->Destroy();
   }
 
diff --git a/content/renderer/mus/BUILD.gn b/content/renderer/mus/BUILD.gn
new file mode 100644
index 0000000..3c126bf
--- /dev/null
+++ b/content/renderer/mus/BUILD.gn
@@ -0,0 +1,22 @@
+# 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.
+
+source_set("mus") {
+  sources = [
+    "compositor_mus_connection.cc",
+    "compositor_mus_connection.h",
+    "render_widget_mus_connection.cc",
+    "render_widget_mus_connection.h",
+    "render_widget_window_tree_client_factory.cc",
+    "render_widget_window_tree_client_factory.h",
+  ]
+
+  deps = [
+    "//base",
+    "//cc",
+    "//components/mus/public/interfaces",
+    "//mojo/converters/blink",
+    "//third_party/WebKit/public:blink",
+  ]
+}
diff --git a/content/renderer/mus/OWNERS b/content/renderer/mus/OWNERS
new file mode 100644
index 0000000..9c070a5
--- /dev/null
+++ b/content/renderer/mus/OWNERS
@@ -0,0 +1 @@
+ben@chromium.org
diff --git a/content/renderer/mus/compositor_mus_connection.cc b/content/renderer/mus/compositor_mus_connection.cc
new file mode 100644
index 0000000..9e0813e
--- /dev/null
+++ b/content/renderer/mus/compositor_mus_connection.cc
@@ -0,0 +1,139 @@
+// 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.
+
+#include "content/renderer/mus/compositor_mus_connection.h"
+
+#include "base/single_thread_task_runner.h"
+#include "content/common/input/web_input_event_traits.h"
+#include "content/renderer/input/input_handler_manager.h"
+#include "content/renderer/mus/render_widget_mus_connection.h"
+#include "mojo/converters/blink/blink_input_events_type_converters.h"
+#include "ui/events/latency_info.h"
+
+namespace content {
+
+CompositorMusConnection::CompositorMusConnection(
+    int routing_id,
+    const scoped_refptr<base::SingleThreadTaskRunner>& main_task_runner,
+    const scoped_refptr<base::SingleThreadTaskRunner>& compositor_task_runner,
+    mojo::InterfaceRequest<mus::mojom::WindowTreeClient> request,
+    InputHandlerManager* input_handler_manager)
+    : routing_id_(routing_id),
+      root_(nullptr),
+      main_task_runner_(main_task_runner),
+      compositor_task_runner_(compositor_task_runner),
+      input_handler_manager_(input_handler_manager) {
+  DCHECK(main_task_runner_->BelongsToCurrentThread());
+  compositor_task_runner_->PostTask(
+      FROM_HERE, base::Bind(&CompositorMusConnection::
+                                CreateWindowTreeConnectionOnCompositorThread,
+                            this, base::Passed(std::move(request))));
+}
+
+void CompositorMusConnection::AttachSurfaceOnMainThread(
+    scoped_ptr<mus::WindowSurfaceBinding> surface_binding) {
+  DCHECK(main_task_runner_->BelongsToCurrentThread());
+  compositor_task_runner_->PostTask(
+      FROM_HERE,
+      base::Bind(&CompositorMusConnection::AttachSurfaceOnCompositorThread,
+                 this, base::Passed(std::move(surface_binding))));
+}
+
+CompositorMusConnection::~CompositorMusConnection() {}
+
+void CompositorMusConnection::AttachSurfaceOnCompositorThread(
+    scoped_ptr<mus::WindowSurfaceBinding> surface_binding) {
+  DCHECK(compositor_task_runner_->BelongsToCurrentThread());
+  window_surface_binding_ = std::move(surface_binding);
+  if (root_) {
+    root_->AttachSurface(mus::mojom::SURFACE_TYPE_DEFAULT,
+                         std::move(window_surface_binding_));
+  }
+}
+
+void CompositorMusConnection::CreateWindowTreeConnectionOnCompositorThread(
+    mojo::InterfaceRequest<mus::mojom::WindowTreeClient> request) {
+  DCHECK(compositor_task_runner_->BelongsToCurrentThread());
+  mus::WindowTreeConnection::Create(
+      this, std::move(request),
+      mus::WindowTreeConnection::CreateType::DONT_WAIT_FOR_EMBED);
+}
+
+void CompositorMusConnection::OnConnectionLostOnMainThread() {
+  DCHECK(main_task_runner_->BelongsToCurrentThread());
+  RenderWidgetMusConnection* connection =
+      RenderWidgetMusConnection::Get(routing_id_);
+  if (!connection)
+    return;
+  connection->OnConnectionLost();
+}
+
+void CompositorMusConnection::OnWindowInputEventOnMainThread(
+    scoped_ptr<blink::WebInputEvent> web_event,
+    const base::Closure& ack) {
+  DCHECK(main_task_runner_->BelongsToCurrentThread());
+  RenderWidgetMusConnection* connection =
+      RenderWidgetMusConnection::Get(routing_id_);
+  if (!connection) {
+    ack.Run();
+    return;
+  }
+  connection->OnWindowInputEvent(std::move(web_event), ack);
+}
+
+void CompositorMusConnection::OnWindowInputEventAckOnMainThread(
+    const base::Closure& ack) {
+  DCHECK(main_task_runner_->BelongsToCurrentThread());
+  compositor_task_runner_->PostTask(FROM_HERE, ack);
+}
+
+void CompositorMusConnection::OnConnectionLost(
+    mus::WindowTreeConnection* connection) {
+  DCHECK(compositor_task_runner_->BelongsToCurrentThread());
+  main_task_runner_->PostTask(
+      FROM_HERE,
+      base::Bind(&CompositorMusConnection::OnConnectionLostOnMainThread, this));
+}
+
+void CompositorMusConnection::OnEmbed(mus::Window* root) {
+  DCHECK(compositor_task_runner_->BelongsToCurrentThread());
+  root_ = root;
+  root_->AddObserver(this);
+  if (window_surface_binding_) {
+    root->AttachSurface(mus::mojom::SURFACE_TYPE_DEFAULT,
+                        std::move(window_surface_binding_));
+  }
+}
+
+void CompositorMusConnection::OnWindowInputEvent(
+    mus::Window* window,
+    const mus::mojom::EventPtr& event) {
+  DCHECK(compositor_task_runner_->BelongsToCurrentThread());
+  scoped_ptr<blink::WebInputEvent> web_event =
+      event.To<scoped_ptr<blink::WebInputEvent>>();
+  // TODO(sad): We probably need to plumb LatencyInfo through Mus.
+  ui::LatencyInfo info;
+  InputEventAckState ack_state = input_handler_manager_->HandleInputEvent(
+      routing_id_, web_event.get(), &info);
+  if (ack_state != INPUT_EVENT_ACK_STATE_NOT_CONSUMED)
+    return;
+  // TODO(sad): Do something more useful once we can do async acks.
+  base::Closure ack = base::Bind(&base::DoNothing);
+  const bool send_ack =
+      WebInputEventTraits::WillReceiveAckFromRenderer(*web_event);
+  if (send_ack) {
+    // Ultimately, this ACK needs to go back to the Mus client lib which is not
+    // thread-safe and lives on the compositor thread. For ACKs that are passed
+    // to the main thread we pass them back to the compositor thread via
+    // OnWindowInputEventAckOnMainThread.
+    ack = base::Bind(
+        &CompositorMusConnection::OnWindowInputEventAckOnMainThread, this, ack);
+  }
+  main_task_runner_->PostTask(
+      FROM_HERE,
+      base::Bind(&CompositorMusConnection::OnWindowInputEventOnMainThread, this,
+                 base::Passed(std::move(web_event)), ack));
+}
+
+}  // namespace content
diff --git a/content/renderer/mus/compositor_mus_connection.h b/content/renderer/mus/compositor_mus_connection.h
new file mode 100644
index 0000000..f7ee6be
--- /dev/null
+++ b/content/renderer/mus/compositor_mus_connection.h
@@ -0,0 +1,83 @@
+// 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.
+
+#ifndef CONTENT_RENDERER_MUS_COMPOSITOR_MUS_CONNECTION_H_
+#define CONTENT_RENDERER_MUS_COMPOSITOR_MUS_CONNECTION_H_
+
+#include "base/bind.h"
+#include "base/macros.h"
+#include "components/mus/public/cpp/window.h"
+#include "components/mus/public/cpp/window_observer.h"
+#include "components/mus/public/cpp/window_tree_connection.h"
+#include "components/mus/public/cpp/window_tree_delegate.h"
+#include "third_party/WebKit/public/web/WebInputEvent.h"
+
+namespace content {
+
+class InputHandlerManager;
+
+// CompositorMusConnection manages the connection to the Mandoline UI Service
+// (Mus) on the compositor thread. For operations that need to happen on the
+// main thread, CompositorMusConnection deals with passing information across
+// threads. CompositorMusConnection is constructed on the main thread. By
+// default all other methods are assumed to run on the compositor thread unless
+// explicited suffixed with OnMainThread.
+class CompositorMusConnection
+    : public mus::WindowTreeDelegate,
+      public mus::WindowObserver,
+      public base::RefCountedThreadSafe<CompositorMusConnection> {
+ public:
+  // Created on main thread.
+  CompositorMusConnection(
+      int routing_id,
+      const scoped_refptr<base::SingleThreadTaskRunner>& main_task_runner,
+      const scoped_refptr<base::SingleThreadTaskRunner>& compositor_task_runner,
+      mojo::InterfaceRequest<mus::mojom::WindowTreeClient> request,
+      InputHandlerManager* input_handler_manager);
+
+  // Attaches the provided |surface_binding| with the mus::Window for the
+  // renderer once it becomes available.
+  void AttachSurfaceOnMainThread(
+      scoped_ptr<mus::WindowSurfaceBinding> surface_binding);
+
+ private:
+  friend class base::RefCountedThreadSafe<CompositorMusConnection>;
+
+  ~CompositorMusConnection() override;
+
+  void AttachSurfaceOnCompositorThread(
+      scoped_ptr<mus::WindowSurfaceBinding> surface_binding);
+
+  void CreateWindowTreeConnectionOnCompositorThread(
+      mojo::InterfaceRequest<mus::mojom::WindowTreeClient> request);
+
+  void OnConnectionLostOnMainThread();
+
+  void OnWindowInputEventOnMainThread(
+      scoped_ptr<blink::WebInputEvent> web_event,
+      const base::Closure& ack);
+
+  void OnWindowInputEventAckOnMainThread(const base::Closure& ack);
+
+  // WindowTreeDelegate implementation:
+  void OnConnectionLost(mus::WindowTreeConnection* connection) override;
+  void OnEmbed(mus::Window* root) override;
+
+  // WindowObserver implementation:
+  void OnWindowInputEvent(mus::Window* window,
+                          const mus::mojom::EventPtr& event) override;
+
+  const int routing_id_;
+  mus::Window* root_;
+  scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
+  scoped_refptr<base::SingleThreadTaskRunner> compositor_task_runner_;
+  InputHandlerManager* const input_handler_manager_;
+  scoped_ptr<mus::WindowSurfaceBinding> window_surface_binding_;
+
+  DISALLOW_COPY_AND_ASSIGN(CompositorMusConnection);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_RENDERER_MUS_COMPOSITOR_MUS_CONNECTION_H_
diff --git a/content/renderer/mus/render_widget_mus_connection.cc b/content/renderer/mus/render_widget_mus_connection.cc
new file mode 100644
index 0000000..5eaaa1a6
--- /dev/null
+++ b/content/renderer/mus/render_widget_mus_connection.cc
@@ -0,0 +1,111 @@
+// 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.
+
+#include "content/renderer/mus/render_widget_mus_connection.h"
+
+#include <map>
+
+#include "base/lazy_instance.h"
+#include "base/macros.h"
+#include "components/mus/public/cpp/context_provider.h"
+#include "components/mus/public/cpp/output_surface.h"
+#include "components/mus/public/interfaces/command_buffer.mojom.h"
+#include "components/mus/public/interfaces/compositor_frame.mojom.h"
+#include "components/mus/public/interfaces/gpu.mojom.h"
+#include "components/mus/public/interfaces/window_tree.mojom.h"
+#include "content/public/common/mojo_shell_connection.h"
+#include "content/renderer/mus/compositor_mus_connection.h"
+#include "content/renderer/render_thread_impl.h"
+#include "content/renderer/render_view_impl.h"
+#include "mojo/application/public/cpp/application_impl.h"
+#include "mojo/converters/geometry/geometry_type_converters.h"
+#include "mojo/converters/surfaces/surfaces_utils.h"
+
+namespace content {
+
+namespace {
+
+typedef std::map<int, RenderWidgetMusConnection*> ConnectionMap;
+base::LazyInstance<ConnectionMap>::Leaky g_connections =
+    LAZY_INSTANCE_INITIALIZER;
+}
+
+void RenderWidgetMusConnection::Bind(
+    mojo::InterfaceRequest<mus::mojom::WindowTreeClient> request) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  RenderThreadImpl* render_thread = RenderThreadImpl::current();
+  compositor_mus_connection_ = new CompositorMusConnection(
+      routing_id_, render_thread->GetCompositorMainThreadTaskRunner(),
+      render_thread->compositor_task_runner(), std::move(request),
+      render_thread->input_handler_manager());
+  if (window_surface_binding_) {
+    compositor_mus_connection_->AttachSurfaceOnMainThread(
+        std::move(window_surface_binding_));
+  }
+}
+
+scoped_ptr<cc::OutputSurface> RenderWidgetMusConnection::CreateOutputSurface() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK(!window_surface_binding_);
+  mus::mojom::GpuPtr gpu_service;
+  MojoShellConnection::Get()->GetApplication()->ConnectToService("mojo:mus",
+                                                                 &gpu_service);
+  mus::mojom::CommandBufferPtr cb;
+  gpu_service->CreateOffscreenGLES2Context(GetProxy(&cb));
+  scoped_refptr<cc::ContextProvider> context_provider(
+      new mus::ContextProvider(cb.PassInterface().PassHandle()));
+  scoped_ptr<cc::OutputSurface> surface(new mus::OutputSurface(
+      context_provider, mus::WindowSurface::Create(&window_surface_binding_)));
+  if (compositor_mus_connection_) {
+    compositor_mus_connection_->AttachSurfaceOnMainThread(
+        std::move(window_surface_binding_));
+  }
+  return surface;
+}
+
+// static
+RenderWidgetMusConnection* RenderWidgetMusConnection::Get(int routing_id) {
+  auto it = g_connections.Get().find(routing_id);
+  if (it != g_connections.Get().end())
+    return it->second;
+  return nullptr;
+}
+
+// static
+RenderWidgetMusConnection* RenderWidgetMusConnection::GetOrCreate(
+    int routing_id) {
+  RenderWidgetMusConnection* connection = Get(routing_id);
+  if (!connection) {
+    connection = new RenderWidgetMusConnection(routing_id);
+    g_connections.Get().insert(std::make_pair(routing_id, connection));
+  }
+  return connection;
+}
+
+RenderWidgetMusConnection::RenderWidgetMusConnection(int routing_id)
+    : routing_id_(routing_id) {
+  DCHECK(routing_id);
+}
+
+RenderWidgetMusConnection::~RenderWidgetMusConnection() {}
+
+void RenderWidgetMusConnection::OnConnectionLost() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  g_connections.Get().erase(routing_id_);
+  delete this;
+}
+
+void RenderWidgetMusConnection::OnWindowInputEvent(
+    scoped_ptr<blink::WebInputEvent> input_event,
+    const base::Closure& ack) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  // TODO(fsamuel): Implement this once the following is complete:
+  // 1. The Mus client lib supports manual event ACKing.
+  // 2. Mus supports event coalescing.
+  // 3. RenderWidget is refactored so that we don't send ACKs to the browser
+  //    process.
+  ack.Run();
+}
+
+}  // namespace content
diff --git a/content/renderer/mus/render_widget_mus_connection.h b/content/renderer/mus/render_widget_mus_connection.h
new file mode 100644
index 0000000..234ce3a
--- /dev/null
+++ b/content/renderer/mus/render_widget_mus_connection.h
@@ -0,0 +1,55 @@
+// 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.
+
+#ifndef CONTENT_RENDERER_MUS_RENDER_WIDGET_MUS_CONNECTION_H_
+#define CONTENT_RENDERER_MUS_RENDER_WIDGET_MUS_CONNECTION_H_
+
+#include "base/macros.h"
+#include "base/threading/thread_checker.h"
+#include "cc/output/output_surface.h"
+#include "components/mus/public/cpp/window_surface.h"
+#include "content/renderer/mus/compositor_mus_connection.h"
+
+namespace content {
+
+class InputHandlerManager;
+
+// Use on main thread.
+class RenderWidgetMusConnection {
+ public:
+  // Bind to a WindowTreeClient request.
+  void Bind(mojo::InterfaceRequest<mus::mojom::WindowTreeClient> request);
+
+  // Create a cc output surface.
+  scoped_ptr<cc::OutputSurface> CreateOutputSurface();
+
+  static RenderWidgetMusConnection* Get(int routing_id);
+
+  // Get the connection from a routing_id, if the connection doesn't exist,
+  // a new connection will be created.
+  static RenderWidgetMusConnection* GetOrCreate(int routing_id);
+
+ private:
+  friend class CompositorMusConnection;
+
+  explicit RenderWidgetMusConnection(int routing_id);
+  ~RenderWidgetMusConnection();
+
+  void OnConnectionLost();
+  void OnWindowInputEvent(scoped_ptr<blink::WebInputEvent> input_event,
+                          const base::Closure& ack);
+
+  const int routing_id_;
+  scoped_ptr<mus::WindowSurfaceBinding> window_surface_binding_;
+  scoped_refptr<CompositorMusConnection> compositor_mus_connection_;
+
+  // Used to verify single threaded access.
+  base::ThreadChecker thread_checker_;
+
+  DISALLOW_COPY_AND_ASSIGN(RenderWidgetMusConnection);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_RENDERER_MUS_RENDER_WIDGET_MUS_CONNECTION_H_
diff --git a/content/renderer/render_widget_window_tree_client_factory.cc b/content/renderer/mus/render_widget_window_tree_client_factory.cc
similarity index 90%
rename from content/renderer/render_widget_window_tree_client_factory.cc
rename to content/renderer/mus/render_widget_window_tree_client_factory.cc
index 9aeb290..f2d1402 100644
--- a/content/renderer/render_widget_window_tree_client_factory.cc
+++ b/content/renderer/mus/render_widget_window_tree_client_factory.cc
@@ -2,14 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/renderer/render_widget_window_tree_client_factory.h"
+#include "content/renderer/mus/render_widget_window_tree_client_factory.h"
 
 #include "base/logging.h"
 #include "base/macros.h"
 #include "components/mus/public/interfaces/window_tree.mojom.h"
 #include "content/common/render_widget_window_tree_client_factory.mojom.h"
 #include "content/public/common/mojo_shell_connection.h"
-#include "content/renderer/render_widget_mus_connection.h"
+#include "content/renderer/mus/render_widget_mus_connection.h"
 #include "mojo/application/public/cpp/application_connection.h"
 #include "mojo/application/public/cpp/interface_factory.h"
 #include "mojo/common/weak_binding_set.h"
@@ -45,7 +45,7 @@
   void Create(mojo::ApplicationConnection* connection,
               mojo::InterfaceRequest<mojom::RenderWidgetWindowTreeClientFactory>
                   request) override {
-    bindings_.AddBinding(this, request.Pass());
+    bindings_.AddBinding(this, std::move(request));
   }
 
   // mojom::RenderWidgetWindowTreeClientFactory implementation.
@@ -54,7 +54,7 @@
       mojo::InterfaceRequest<mus::mojom::WindowTreeClient> request) override {
     RenderWidgetMusConnection* connection =
         RenderWidgetMusConnection::GetOrCreate(routing_id);
-    connection->Bind(request.Pass());
+    connection->Bind(std::move(request));
   }
 
   mojo::WeakBindingSet<mojom::RenderWidgetWindowTreeClientFactory> bindings_;
diff --git a/content/renderer/mus/render_widget_window_tree_client_factory.h b/content/renderer/mus/render_widget_window_tree_client_factory.h
new file mode 100644
index 0000000..f3b3b73
--- /dev/null
+++ b/content/renderer/mus/render_widget_window_tree_client_factory.h
@@ -0,0 +1,14 @@
+// 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.
+
+#ifndef CONTENT_RENDERER_MUS_RENDER_WIDGET_WINDOW_TREE_CLIENT_FACTORY_H_
+#define CONTENT_RENDERER_MUS_RENDER_WIDGET_WINDOW_TREE_CLIENT_FACTORY_H_
+
+namespace content {
+
+void CreateRenderWidgetWindowTreeClientFactory();
+
+}  // namespace content
+
+#endif  // CONTENT_RENDERER_MUS_RENDER_WIDGET_WINDOW_TREE_CLIENT_FACTORY_H_
diff --git a/content/renderer/npapi/webplugin_delegate_proxy.cc b/content/renderer/npapi/webplugin_delegate_proxy.cc
index 054fa47d..a77e844 100644
--- a/content/renderer/npapi/webplugin_delegate_proxy.cc
+++ b/content/renderer/npapi/webplugin_delegate_proxy.cc
@@ -96,26 +96,11 @@
 class ResourceClientProxy : public WebPluginResourceClient {
  public:
   ResourceClientProxy(PluginChannelHost* channel, int instance_id)
-    : channel_(channel), instance_id_(instance_id), resource_id_(0),
-      multibyte_response_expected_(false) {
+    : channel_(channel), instance_id_(instance_id), resource_id_(0) {
   }
 
   ~ResourceClientProxy() override {}
 
-  void Initialize(unsigned long resource_id, const GURL& url, int notify_id) {
-    resource_id_ = resource_id;
-    channel_->Send(new PluginMsg_HandleURLRequestReply(
-        instance_id_, resource_id, url, notify_id));
-  }
-
-  void InitializeForSeekableStream(unsigned long resource_id,
-                                   int range_request_id) {
-    resource_id_ = resource_id;
-    multibyte_response_expected_ = true;
-    channel_->Send(new PluginMsg_HTTPRangeRequestReply(
-        instance_id_, resource_id, range_request_id));
-  }
-
   // PluginResourceClient implementation:
   void WillSendRequest(const GURL& url, int http_status_code) override {
     DCHECK(channel_.get() != NULL);
@@ -173,19 +158,12 @@
     base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
   }
 
-  bool IsMultiByteResponseExpected() override {
-    return multibyte_response_expected_;
-  }
-
   int ResourceId() override { return resource_id_; }
 
  private:
   scoped_refptr<PluginChannelHost> channel_;
   int instance_id_;
   unsigned long resource_id_;
-  // Set to true if the response expected is a multibyte response.
-  // For e.g. response for a HTTP byte range request.
-  bool multibyte_response_expected_;
 };
 
 }  // namespace
@@ -386,44 +364,6 @@
   return channel_host_->Send(msg);
 }
 
-void WebPluginDelegateProxy::SendJavaScriptStream(const GURL& url,
-                                                  const std::string& result,
-                                                  bool success,
-                                                  int notify_id) {
-  Send(new PluginMsg_SendJavaScriptStream(
-      instance_id_, url, result, success, notify_id));
-}
-
-void WebPluginDelegateProxy::DidReceiveManualResponse(
-    const GURL& url, const std::string& mime_type,
-    const std::string& headers, uint32 expected_length,
-    uint32 last_modified) {
-  PluginMsg_DidReceiveResponseParams params;
-  params.id = 0;
-  params.mime_type = mime_type;
-  params.headers = headers;
-  params.expected_length = expected_length;
-  params.last_modified = last_modified;
-  Send(new PluginMsg_DidReceiveManualResponse(instance_id_, url, params));
-}
-
-void WebPluginDelegateProxy::DidReceiveManualData(const char* buffer,
-                                                  int length) {
-  DCHECK_GT(length, 0);
-  std::vector<char> data;
-  data.resize(static_cast<size_t>(length));
-  memcpy(&data.front(), buffer, length);
-  Send(new PluginMsg_DidReceiveManualData(instance_id_, data));
-}
-
-void WebPluginDelegateProxy::DidFinishManualLoading() {
-  Send(new PluginMsg_DidFinishManualLoading(instance_id_));
-}
-
-void WebPluginDelegateProxy::DidManualLoadFail() {
-  Send(new PluginMsg_DidManualLoadFail(instance_id_));
-}
-
 bool WebPluginDelegateProxy::OnMessageReceived(const IPC::Message& msg) {
   GetContentClient()->SetActiveURL(page_url_);
 
@@ -438,10 +378,7 @@
     IPC_MESSAGE_HANDLER(PluginHostMsg_ResolveProxy, OnResolveProxy)
     IPC_MESSAGE_HANDLER(PluginHostMsg_SetCookie, OnSetCookie)
     IPC_MESSAGE_HANDLER(PluginHostMsg_GetCookies, OnGetCookies)
-    IPC_MESSAGE_HANDLER(PluginHostMsg_URLRequest, OnHandleURLRequest)
     IPC_MESSAGE_HANDLER(PluginHostMsg_CancelDocumentLoad, OnCancelDocumentLoad)
-    IPC_MESSAGE_HANDLER(PluginHostMsg_InitiateHTTPRangeRequest,
-                        OnInitiateHTTPRangeRequest)
     IPC_MESSAGE_HANDLER(PluginHostMsg_DidStartLoading, OnDidStartLoading)
     IPC_MESSAGE_HANDLER(PluginHostMsg_DidStopLoading, OnDidStopLoading)
     IPC_MESSAGE_HANDLER(PluginHostMsg_DeferResourceLoading,
@@ -742,12 +679,6 @@
   return success;
 }
 
-void WebPluginDelegateProxy::DidFinishLoadWithReason(
-    const GURL& url, NPReason reason, int notify_id) {
-  Send(new PluginMsg_DidFinishLoadWithReason(
-      instance_id_, url, reason, notify_id));
-}
-
 void WebPluginDelegateProxy::SetFocus(bool focused) {
   Send(new PluginMsg_SetFocus(instance_id_, focused));
 #if defined(OS_WIN)
@@ -1066,75 +997,6 @@
   transport_store_painted_.Union(rect);
 }
 
-void WebPluginDelegateProxy::OnHandleURLRequest(
-    const PluginHostMsg_URLRequest_Params& params) {
-  const char* data = NULL;
-  if (params.buffer.size())
-    data = &params.buffer[0];
-
-  const char* target = NULL;
-  if (params.target.length())
-    target = params.target.c_str();
-
-  plugin_->HandleURLRequest(
-      params.url.c_str(), params.method.c_str(), target, data,
-      static_cast<unsigned int>(params.buffer.size()), params.notify_id,
-      params.popups_allowed, params.notify_redirects);
-}
-
-WebPluginResourceClient* WebPluginDelegateProxy::CreateResourceClient(
-    unsigned long resource_id, const GURL& url, int notify_id) {
-  if (!channel_host_.get())
-    return NULL;
-
-  ResourceClientProxy* proxy =
-      new ResourceClientProxy(channel_host_.get(), instance_id_);
-  proxy->Initialize(resource_id, url, notify_id);
-  return proxy;
-}
-
-WebPluginResourceClient* WebPluginDelegateProxy::CreateSeekableResourceClient(
-    unsigned long resource_id, int range_request_id) {
-  if (!channel_host_.get())
-    return NULL;
-
-  ResourceClientProxy* proxy =
-      new ResourceClientProxy(channel_host_.get(), instance_id_);
-  proxy->InitializeForSeekableStream(resource_id, range_request_id);
-  return proxy;
-}
-
-void WebPluginDelegateProxy::FetchURL(unsigned long resource_id,
-                                      int notify_id,
-                                      const GURL& url,
-                                      const GURL& first_party_for_cookies,
-                                      const std::string& method,
-                                      const char* buf,
-                                      unsigned int len,
-                                      const Referrer& referrer,
-                                      bool notify_redirects,
-                                      bool is_plugin_src_load,
-                                      int origin_pid,
-                                      int render_frame_id,
-                                      int render_view_id) {
-  PluginMsg_FetchURL_Params params;
-  params.resource_id = resource_id;
-  params.notify_id = notify_id;
-  params.url = url;
-  params.first_party_for_cookies = first_party_for_cookies;
-  params.method = method;
-  if (len) {
-    params.post_data.resize(len);
-    memcpy(&params.post_data.front(), buf, len);
-  }
-  params.referrer = referrer.url;
-  params.referrer_policy = referrer.policy;
-  params.notify_redirect = notify_redirects;
-  params.is_plugin_src_load = is_plugin_src_load;
-  params.render_frame_id = render_frame_id;
-  Send(new PluginMsg_FetchURL(instance_id_, params));
-}
-
 #if defined(OS_MACOSX)
 void WebPluginDelegateProxy::OnFocusChanged(bool focused) {
   if (render_view_)
@@ -1155,14 +1017,6 @@
   plugin_->CancelDocumentLoad();
 }
 
-void WebPluginDelegateProxy::OnInitiateHTTPRangeRequest(
-    const std::string& url,
-    const std::string& range_info,
-    int range_request_id) {
-  plugin_->InitiateHTTPRangeRequest(
-      url.c_str(), range_info.c_str(), range_request_id);
-}
-
 void WebPluginDelegateProxy::OnDidStartLoading() {
   plugin_->DidStartLoading();
 }
diff --git a/content/renderer/npapi/webplugin_delegate_proxy.h b/content/renderer/npapi/webplugin_delegate_proxy.h
index 64eab9df..ad9a66b8 100644
--- a/content/renderer/npapi/webplugin_delegate_proxy.h
+++ b/content/renderer/npapi/webplugin_delegate_proxy.h
@@ -67,9 +67,6 @@
   NPObject* GetPluginScriptableObject() override;
   struct _NPP* GetPluginNPP() override;
   bool GetFormValue(base::string16* value) override;
-  void DidFinishLoadWithReason(const GURL& url,
-                               NPReason reason,
-                               int notify_id) override;
   void SetFocus(bool focused) override;
   bool HandleInputEvent(const blink::WebInputEvent& event,
                         WebCursor::CursorInfo* cursor) override;
@@ -111,39 +108,6 @@
   // IPC::Sender implementation:
   bool Send(IPC::Message* msg) override;
 
-  void SendJavaScriptStream(const GURL& url,
-                            const std::string& result,
-                            bool success,
-                            int notify_id) override;
-
-  void DidReceiveManualResponse(const GURL& url,
-                                const std::string& mime_type,
-                                const std::string& headers,
-                                uint32 expected_length,
-                                uint32 last_modified) override;
-  void DidReceiveManualData(const char* buffer, int length) override;
-  void DidFinishManualLoading() override;
-  void DidManualLoadFail() override;
-  WebPluginResourceClient* CreateResourceClient(unsigned long resource_id,
-                                                const GURL& url,
-                                                int notify_id) override;
-  WebPluginResourceClient* CreateSeekableResourceClient(
-      unsigned long resource_id,
-      int range_request_id) override;
-  void FetchURL(unsigned long resource_id,
-                int notify_id,
-                const GURL& url,
-                const GURL& first_party_for_cookies,
-                const std::string& method,
-                const char* buf,
-                unsigned int len,
-                const Referrer& referrer,
-                bool notify_redirects,
-                bool is_plugin_src_load,
-                int origin_pid,
-                int render_frame_id,
-                int render_view_id) override;
-
   gfx::PluginWindowHandle GetPluginWindowHandle();
 
  protected:
diff --git a/content/renderer/npapi/webplugin_impl.cc b/content/renderer/npapi/webplugin_impl.cc
index 91ffa938..1c9c7981 100644
--- a/content/renderer/npapi/webplugin_impl.cc
+++ b/content/renderer/npapi/webplugin_impl.cc
@@ -362,23 +362,6 @@
     delegate_->UpdateGeometry(new_geometry.window_rect, new_geometry.clip_rect);
   }
 
-  // Initiate a download on the plugin url. This should be done for the
-  // first update geometry sequence. We need to ensure that the plugin
-  // receives the geometry update before it starts receiving data.
-  if (first_geometry_update_) {
-    // An empty url corresponds to an EMBED tag with no src attribute.
-    if (!load_manually_ && plugin_url_.is_valid()) {
-      // The Flash plugin hangs for a while if it receives data before
-      // receiving valid plugin geometry. By valid geometry we mean the
-      // geometry received by a call to setFrameRect in the Webkit
-      // layout code path. To workaround this issue we download the
-      // plugin source url on a timer.
-      base::ThreadTaskRunnerHandle::Get()->PostTask(
-          FROM_HERE, base::Bind(&WebPluginImpl::OnDownloadPluginSrcUrl,
-                                weak_factory_.GetWeakPtr()));
-    }
-  }
-
 #if defined(OS_WIN)
   // Don't cache the geometry during the first geometry update. The first
   // geometry update sequence is received when Widget::setParent is called.
@@ -439,58 +422,6 @@
              : WebInputEventResult::NotHandled;
 }
 
-void WebPluginImpl::didReceiveResponse(const WebURLResponse& response) {
-  ignore_response_error_ = false;
-
-  ResponseInfo response_info;
-  GetResponseInfo(response, &response_info);
-
-  delegate_->DidReceiveManualResponse(
-      response_info.url,
-      response_info.mime_type,
-      GetAllHeaders(response),
-      response_info.expected_length,
-      response_info.last_modified);
-}
-
-void WebPluginImpl::didReceiveData(const char* data, int data_length) {
-  delegate_->DidReceiveManualData(data, data_length);
-}
-
-void WebPluginImpl::didFinishLoading() {
-  delegate_->DidFinishManualLoading();
-}
-
-void WebPluginImpl::didFailLoading(const WebURLError& error) {
-  if (!ignore_response_error_)
-    delegate_->DidManualLoadFail();
-}
-
-void WebPluginImpl::didFinishLoadingFrameRequest(
-    const WebURL& url, void* notify_data) {
-  if (delegate_) {
-    // We're converting a void* into an arbitrary int id.  Though
-    // these types are the same size on all the platforms we support,
-    // the compiler may complain as though they are different, so to
-    // make the casting gods happy go through an intptr_t (the union
-    // of void* and int) rather than converting straight across.
-    delegate_->DidFinishLoadWithReason(
-        url, NPRES_DONE, reinterpret_cast<intptr_t>(notify_data));
-  }
-}
-
-void WebPluginImpl::didFailLoadingFrameRequest(
-    const WebURL& url, void* notify_data, const WebURLError& error) {
-  if (!delegate_)
-    return;
-
-  NPReason reason =
-      error.reason == net::ERR_ABORTED ? NPRES_USER_BREAK : NPRES_NETWORK_ERR;
-  // See comment in didFinishLoadingFrameRequest about the cast here.
-  delegate_->DidFinishLoadWithReason(
-      url, reason, reinterpret_cast<intptr_t>(notify_data));
-}
-
 bool WebPluginImpl::isPlaceholder() {
   return false;
 }
@@ -564,8 +495,7 @@
       file_path_(file_path),
       mime_type_(base::ToLowerASCII(base::UTF16ToASCII(
           base::StringPiece16(params.mimeType)))),
-      loader_client_(this),
-      weak_factory_(this) {
+      loader_client_(this) {
   DCHECK_EQ(params.attributeNames.size(), params.attributeValues.size());
 
   for (size_t i = 0; i < params.attributeNames.size(); ++i) {
@@ -700,7 +630,6 @@
     const char* target,
     const char* buf,
     unsigned int len,
-    int notify_id,
     ReferrerValue referrer_flag) {
   // If there is no target, there is nothing to do
   if (!target)
@@ -764,8 +693,7 @@
     }
   }
 
-  container_->loadFrameRequest(
-      request, target_str, notify_id != 0, reinterpret_cast<void*>(notify_id));
+  container_->loadFrameRequest(request, target_str);
   return ROUTED;
 }
 
@@ -903,12 +831,6 @@
     container_->invalidateRect(rect);
 }
 
-void WebPluginImpl::OnDownloadPluginSrcUrl() {
-  HandleURLRequestInternal(
-      plugin_url_.spec().c_str(), "GET", NULL, NULL, 0, 0, false, DOCUMENT_URL,
-      false, true);
-}
-
 WebPluginResourceClient* WebPluginImpl::GetClientFromLoader(
     WebURLLoader* loader) {
   ClientInfo* client_info = GetClientInfoFromLoader(loader);
@@ -981,8 +903,6 @@
                                        const WebURLResponse& response) {
   // TODO(jam): THIS LOGIC IS COPIED IN PluginURLFetcher::OnReceivedResponse
   // until kDirectNPAPIRequests is the default and we can remove this old path.
-  static const int kHttpPartialResponseStatusCode = 206;
-  static const int kHttpResponseSuccessStatusCode = 200;
 
   WebPluginResourceClient* client = GetClientFromLoader(loader);
   if (!client)
@@ -994,64 +914,6 @@
   if (!client_info)
     return;
 
-  bool request_is_seekable = true;
-  if (client->IsMultiByteResponseExpected()) {
-    if (response.httpStatusCode() == kHttpPartialResponseStatusCode) {
-      ClientInfo* client_info = GetClientInfoFromLoader(loader);
-      if (!client_info)
-        return;
-      if (HandleHttpMultipartResponse(response, client)) {
-        // Multiple ranges requested, data will be delivered by
-        // MultipartResponseDelegate.
-        client_info->data_offset = 0;
-        return;
-      }
-      int64 upper_bound = 0, instance_size = 0;
-      // Single range requested - go through original processing for
-      // non-multipart requests, but update data offset.
-      MultipartResponseDelegate::ReadContentRanges(response,
-                                                   &client_info->data_offset,
-                                                   &upper_bound,
-                                                   &instance_size);
-    } else if (response.httpStatusCode() == kHttpResponseSuccessStatusCode) {
-      RenderThreadImpl::current()->RecordAction(
-          base::UserMetricsAction("Plugin_200ForByteRange"));
-      // If the client issued a byte range request and the server responds with
-      // HTTP 200 OK, it indicates that the server does not support byte range
-      // requests.
-      // We need to emulate Firefox behavior by doing the following:-
-      // 1. Destroy the plugin instance in the plugin process. Ensure that
-      //    existing resource requests initiated for the plugin instance
-      //    continue to remain valid.
-      // 2. Create a new plugin instance and notify it about the response
-      //    received here.
-      if (!ReinitializePluginForResponse(loader)) {
-        NOTREACHED();
-        return;
-      }
-
-      // The server does not support byte range requests. No point in creating
-      // seekable streams.
-      request_is_seekable = false;
-
-      delete client;
-      client = NULL;
-
-      // Create a new resource client for this request.
-      for (size_t i = 0; i < clients_.size(); ++i) {
-        if (clients_[i].loader.get() == loader) {
-          WebPluginResourceClient* resource_client =
-              delegate_->CreateResourceClient(clients_[i].id, plugin_url_, 0);
-          clients_[i].client = resource_client;
-          client = resource_client;
-          break;
-        }
-      }
-
-      DCHECK(client != NULL);
-    }
-  }
-
   // Calling into a plugin could result in reentrancy if the plugin yields
   // control to the OS like entering a modal loop etc. Prevent this by
   // stopping further loading until the plugin notifies us that it is ready to
@@ -1063,7 +925,7 @@
       GetAllHeaders(response),
       response_info.expected_length,
       response_info.last_modified,
-      request_is_seekable);
+      true);
 
   // Bug http://b/issue?id=925559. The flash plugin would not handle the HTTP
   // error codes in the stream header and as a result, was unaware of the
@@ -1161,121 +1023,6 @@
     container_->allowScriptObjects();
 }
 
-void WebPluginImpl::HandleURLRequest(const char* url,
-                                     const char* method,
-                                     const char* target,
-                                     const char* buf,
-                                     unsigned int len,
-                                     int notify_id,
-                                     bool popups_allowed,
-                                     bool notify_redirects) {
-  // GetURL/PostURL requests initiated explicitly by plugins should specify the
-  // plugin SRC url as the referrer if it is available.
-  HandleURLRequestInternal(
-      url, method, target, buf, len, notify_id, popups_allowed, PLUGIN_SRC,
-      notify_redirects, false);
-}
-
-void WebPluginImpl::HandleURLRequestInternal(const char* url,
-                                             const char* method,
-                                             const char* target,
-                                             const char* buf,
-                                             unsigned int len,
-                                             int notify_id,
-                                             bool popups_allowed,
-                                             ReferrerValue referrer_flag,
-                                             bool notify_redirects,
-                                             bool is_plugin_src_load) {
-  // For this request, we either route the output to a frame
-  // because a target has been specified, or we handle the request
-  // here, i.e. by executing the script if it is a javascript url
-  // or by initiating a download on the URL, etc. There is one special
-  // case in that the request is a javascript url and the target is "_self",
-  // in which case we route the output to the plugin rather than routing it
-  // to the plugin's frame.
-  bool is_javascript_url =
-      url::FindAndCompareScheme(url, strlen(url), url::kJavaScriptScheme, NULL);
-  RoutingStatus routing_status = RouteToFrame(
-      url, is_javascript_url, popups_allowed, method, target, buf, len,
-      notify_id, referrer_flag);
-  if (routing_status == ROUTED)
-    return;
-
-  if (is_javascript_url) {
-    GURL gurl(url);
-    WebString result = container_->executeScriptURL(gurl, popups_allowed);
-
-    // delegate_ could be NULL because executeScript caused the container to
-    // be deleted.
-    if (delegate_) {
-      delegate_->SendJavaScriptStream(
-          gurl, result.utf8(), !result.isNull(), notify_id);
-    }
-
-    return;
-  }
-
-  unsigned long resource_id = GetNextResourceId();
-  if (!resource_id)
-    return;
-
-  GURL complete_url = CompleteURL(url);
-  // Remove when flash bug is fixed. http://crbug.com/40016.
-  if (!WebPluginImpl::IsValidUrl(complete_url, referrer_flag))
-    return;
-
-  // If the RouteToFrame call returned a failure then inform the result
-  // back to the plugin asynchronously.
-  if ((routing_status == INVALID_URL) ||
-      (routing_status == GENERAL_FAILURE)) {
-    WebPluginResourceClient* resource_client = delegate_->CreateResourceClient(
-        resource_id, complete_url, notify_id);
-    if (resource_client)
-      resource_client->DidFail(resource_id);
-    return;
-  }
-
-  // CreateResourceClient() sends a synchronous IPC message so it's possible
-  // that TearDownPluginInstance() may have been called in the nested
-  // message loop.  If so, don't start the request.
-  if (!delegate_)
-    return;
-
-  if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kDisableDirectNPAPIRequests)) {
-    // We got here either because the plugin called GetURL/PostURL, or because
-    // we're fetching the data for an embed tag. If we're in multi-process mode,
-    // we want to fetch the data in the plugin process as the renderer won't be
-    // able to request any origin when site isolation is in place. So bounce
-    // this request back to the plugin process which will use ResourceDispatcher
-    // to fetch the url.
-
-    // TODO(jam): any better way of getting this? Can't find a way to get
-    // frame()->loader()->outgoingReferrer() which
-    // WebFrameImpl::setReferrerForRequest does.
-    WebURLRequest request(complete_url);
-    SetReferrer(&request, referrer_flag);
-    Referrer referrer(
-        GURL(request.httpHeaderField(WebString::fromUTF8("Referer"))),
-        request.referrerPolicy());
-
-    GURL first_party_for_cookies = webframe_->document().firstPartyForCookies();
-    delegate_->FetchURL(resource_id, notify_id, complete_url,
-                        first_party_for_cookies, method, buf, len, referrer,
-                        notify_redirects, is_plugin_src_load, 0,
-                        render_frame_->GetRoutingID(),
-                        render_view_->GetRoutingID());
-  } else {
-    WebPluginResourceClient* resource_client = delegate_->CreateResourceClient(
-        resource_id, complete_url, notify_id);
-    if (!resource_client)
-      return;
-    InitiateHTTPRequest(resource_id, resource_client, complete_url, method, buf,
-                        len, NULL, referrer_flag, notify_redirects,
-                        is_plugin_src_load);
-  }
-}
-
 unsigned long WebPluginImpl::GetNextResourceId() {
   if (!webframe_)
     return 0;
@@ -1285,67 +1032,6 @@
   return view->createUniqueIdentifierForRequest();
 }
 
-bool WebPluginImpl::InitiateHTTPRequest(unsigned long resource_id,
-                                        WebPluginResourceClient* client,
-                                        const GURL& url,
-                                        const char* method,
-                                        const char* buf,
-                                        int buf_len,
-                                        const char* range_info,
-                                        ReferrerValue referrer_flag,
-                                        bool notify_redirects,
-                                        bool is_plugin_src_load) {
-  if (!client) {
-    NOTREACHED();
-    return false;
-  }
-
-  ClientInfo info;
-  info.id = resource_id;
-  info.client = client;
-  info.request.initialize();
-  info.request.setURL(url);
-  info.request.setFirstPartyForCookies(
-      webframe_->document().firstPartyForCookies());
-  info.request.setRequestorProcessID(delegate_->GetProcessId());
-  // TODO(mkwst): Is this a request for a plugin object itself
-  // (RequestContextObject), or a request that the plugin makes
-  // (RequestContextPlugin)?
-  info.request.setRequestContext(WebURLRequest::RequestContextPlugin);
-  info.request.setHTTPMethod(WebString::fromUTF8(method));
-  // ServiceWorker is disabled for NPAPI.
-  info.request.setSkipServiceWorker(true);
-  info.pending_failure_notification = false;
-  info.notify_redirects = notify_redirects;
-  info.is_plugin_src_load = is_plugin_src_load;
-  info.data_offset = 0;
-
-  if (range_info) {
-    info.request.addHTTPHeaderField(WebString::fromUTF8("Range"),
-                                    WebString::fromUTF8(range_info));
-  }
-
-  if (strcmp(method, "POST") == 0) {
-    // Adds headers or form data to a request.  This must be called before
-    // we initiate the actual request.
-    SetPostData(&info.request, buf, buf_len);
-  }
-
-  SetReferrer(&info.request, referrer_flag);
-
-  WebURLLoaderOptions options;
-  options.allowCredentials = true;
-  options.crossOriginRequestPolicy =
-      WebURLLoaderOptions::CrossOriginRequestPolicyAllow;
-  info.loader.reset(webframe_->createAssociatedURLLoader(options));
-  if (!info.loader.get())
-    return false;
-  info.loader->loadAsynchronously(info.request, &loader_client_);
-
-  clients_.push_back(info);
-  return true;
-}
-
 void WebPluginImpl::CancelDocumentLoad() {
   if (webframe_) {
     ignore_response_error_ = true;
@@ -1353,25 +1039,6 @@
   }
 }
 
-void WebPluginImpl::InitiateHTTPRangeRequest(
-    const char* url, const char* range_info, int range_request_id) {
-  unsigned long resource_id = GetNextResourceId();
-  if (!resource_id)
-    return;
-
-  GURL complete_url = CompleteURL(url);
-  // Remove when flash bug is fixed. http://crbug.com/40016.
-  if (!WebPluginImpl::IsValidUrl(complete_url,
-                                 load_manually_ ? NO_REFERRER : PLUGIN_SRC))
-    return;
-
-  WebPluginResourceClient* resource_client =
-      delegate_->CreateSeekableResourceClient(resource_id, range_request_id);
-  InitiateHTTPRequest(
-      resource_id, resource_client, complete_url, "GET", NULL, 0, range_info,
-      load_manually_ ? NO_REFERRER : PLUGIN_SRC, false, false);
-}
-
 void WebPluginImpl::DidStartLoading() {
   if (render_view_.get()) {
     // TODO(darin): Make is_loading_ be a counter!
@@ -1539,7 +1206,6 @@
   // This needs to be called now and not in the destructor since the
   // webframe_ might not be valid anymore.
   webframe_ = NULL;
-  weak_factory_.InvalidateWeakPtrs();
 }
 
 void WebPluginImpl::SetReferrer(blink::WebURLRequest* request,
diff --git a/content/renderer/npapi/webplugin_impl.h b/content/renderer/npapi/webplugin_impl.h
index 3eb157eb..39e3226 100644
--- a/content/renderer/npapi/webplugin_impl.h
+++ b/content/renderer/npapi/webplugin_impl.h
@@ -86,15 +86,10 @@
   blink::WebInputEventResult handleInputEvent(
       const blink::WebInputEvent& event,
       blink::WebCursorInfo& cursor_info) override;
-  void didReceiveResponse(const blink::WebURLResponse& response) override;
-  void didReceiveData(const char* data, int data_length) override;
-  void didFinishLoading() override;
-  void didFailLoading(const blink::WebURLError& error) override;
-  void didFinishLoadingFrameRequest(const blink::WebURL& url,
-                                    void* notify_data) override;
-  void didFailLoadingFrameRequest(const blink::WebURL& url,
-                                  void* notify_data,
-                                  const blink::WebURLError& error) override;
+  void didReceiveResponse(const blink::WebURLResponse& response) override {}
+  void didReceiveData(const char* data, int data_length) override {}
+  void didFinishLoading() override {}
+  void didFailLoading(const blink::WebURLError& error) override {}
   bool isPlaceholder() override;
 
   // WebPlugin implementation:
@@ -112,18 +107,7 @@
                  const std::string& cookie) override;
   std::string GetCookies(const GURL& url,
                          const GURL& first_party_for_cookies) override;
-  void HandleURLRequest(const char* url,
-                        const char* method,
-                        const char* target,
-                        const char* buf,
-                        unsigned int len,
-                        int notify_id,
-                        bool popups_allowed,
-                        bool notify_redirects) override;
   void CancelDocumentLoad() override;
-  void InitiateHTTPRangeRequest(const char* url,
-                                const char* range_info,
-                                int pending_request_id) override;
   void DidStartLoading() override;
   void DidStopLoading() override;
   bool IsOffTheRecord() override;
@@ -175,26 +159,12 @@
                              const char* target,
                              const char* buf,
                              unsigned int len,
-                             int notify_id,
                              ReferrerValue referrer_flag);
 
   // Returns the next avaiable resource id. Returns 0 if the operation fails.
   // It may fail if the page has already been closed.
   unsigned long GetNextResourceId();
 
-  // Initiates HTTP GET/POST requests.
-  // Returns true on success.
-  bool InitiateHTTPRequest(unsigned long resource_id,
-                           WebPluginResourceClient* client,
-                           const GURL& url,
-                           const char* method,
-                           const char* buf,
-                           int len,
-                           const char* range_info,
-                           ReferrerValue referrer_flag,
-                           bool notify_redirects,
-                           bool check_mixed_scripting);
-
   gfx::Rect GetWindowClipRect(const gfx::Rect& rect);
 
   // Sets the actual Widget for the plugin.
@@ -239,24 +209,10 @@
   bool HandleHttpMultipartResponse(const blink::WebURLResponse& response,
                                    WebPluginResourceClient* client);
 
-  void HandleURLRequestInternal(const char* url,
-                                const char* method,
-                                const char* target,
-                                const char* buf,
-                                unsigned int len,
-                                int notify_id,
-                                bool popups_allowed,
-                                ReferrerValue referrer_flag,
-                                bool notify_redirects,
-                                bool check_mixed_scripting);
-
   // Tears down the existing plugin instance and creates a new plugin instance
   // to handle the response identified by the loader parameter.
   bool ReinitializePluginForResponse(blink::WebURLLoader* loader);
 
-  // Delayed task for downloading the plugin source URL.
-  void OnDownloadPluginSrcUrl();
-
   struct ClientInfo;
 
   // Helper functions
@@ -359,8 +315,6 @@
 
   LoaderClient loader_client_;
 
-  base::WeakPtrFactory<WebPluginImpl> weak_factory_;
-
   DISALLOW_COPY_AND_ASSIGN(WebPluginImpl);
 };
 
diff --git a/content/renderer/p2p/ipc_network_manager.cc b/content/renderer/p2p/ipc_network_manager.cc
index f702e9e..1c9acb9 100644
--- a/content/renderer/p2p/ipc_network_manager.cc
+++ b/content/renderer/p2p/ipc_network_manager.cc
@@ -80,10 +80,10 @@
   if (!network_list_received_)
     network_list_received_ = true;
 
-  // Update the default local interfaces.
-  set_default_local_addresses(
-      jingle_glue::IPAddressNumberToIPAddress(default_ipv4_local_address),
-      jingle_glue::IPAddressNumberToIPAddress(default_ipv6_local_address));
+  // Default addresses should be set only when they are in the filtered list of
+  // network addresses.
+  bool use_default_ipv4_address = false;
+  bool use_default_ipv6_address = false;
 
   // rtc::Network uses these prefix_length to compare network
   // interfaces discovered.
@@ -102,6 +102,7 @@
 
     rtc::InterfaceAddress iface_addr;
     if (it->address.size() == net::kIPv4AddressSize) {
+      use_default_ipv4_address |= (default_ipv4_local_address == it->address);
       iface_addr = rtc::InterfaceAddress(ip_address);
     } else {
       DCHECK(it->address.size() == net::kIPv6AddressSize);
@@ -114,11 +115,26 @@
           rtc::IPIsPrivate(iface_addr)) {
         continue;
       }
+
+      use_default_ipv6_address |= (default_ipv6_local_address == it->address);
     }
     network->AddIP(iface_addr);
     networks.push_back(network.release());
   }
 
+  // Update the default local addresses.
+  rtc::IPAddress ipv4_default;
+  rtc::IPAddress ipv6_defualt;
+  if (use_default_ipv4_address) {
+    ipv4_default =
+        jingle_glue::IPAddressNumberToIPAddress(default_ipv4_local_address);
+  }
+  if (use_default_ipv6_address) {
+    ipv6_defualt =
+        jingle_glue::IPAddressNumberToIPAddress(default_ipv6_local_address);
+  }
+  set_default_local_addresses(ipv4_default, ipv6_defualt);
+
   if (base::CommandLine::ForCurrentProcess()->HasSwitch(
           switches::kAllowLoopbackInPeerConnection)) {
     std::string name_v4("loopback_ipv4");
diff --git a/content/renderer/pepper/pepper_plugin_instance_impl.cc b/content/renderer/pepper/pepper_plugin_instance_impl.cc
index 811c107..d23f9f96 100644
--- a/content/renderer/pepper/pepper_plugin_instance_impl.cc
+++ b/content/renderer/pepper/pepper_plugin_instance_impl.cc
@@ -3116,7 +3116,7 @@
 
   WebString target_str = WebString::fromUTF8(target);
   blink::WebScopedUserGesture user_gesture(CurrentUserGestureToken());
-  container_->loadFrameRequest(web_request, target_str, false, NULL);
+  container_->loadFrameRequest(web_request, target_str);
   return PP_OK;
 }
 
diff --git a/content/renderer/pepper/pepper_webplugin_impl.cc b/content/renderer/pepper/pepper_webplugin_impl.cc
index e4bf44d6..0f53f2a8 100644
--- a/content/renderer/pepper/pepper_webplugin_impl.cc
+++ b/content/renderer/pepper/pepper_webplugin_impl.cc
@@ -254,14 +254,6 @@
     document_loader->didFail(NULL, error);
 }
 
-void PepperWebPluginImpl::didFinishLoadingFrameRequest(const blink::WebURL& url,
-                                                       void* notify_data) {}
-
-void PepperWebPluginImpl::didFailLoadingFrameRequest(
-    const blink::WebURL& url,
-    void* notify_data,
-    const blink::WebURLError& error) {}
-
 bool PepperWebPluginImpl::hasSelection() const {
   return !selectionAsText().isEmpty();
 }
diff --git a/content/renderer/pepper/pepper_webplugin_impl.h b/content/renderer/pepper/pepper_webplugin_impl.h
index 6046406..5bfa988 100644
--- a/content/renderer/pepper/pepper_webplugin_impl.h
+++ b/content/renderer/pepper/pepper_webplugin_impl.h
@@ -62,11 +62,6 @@
   void didReceiveData(const char* data, int data_length) override;
   void didFinishLoading() override;
   void didFailLoading(const blink::WebURLError&) override;
-  void didFinishLoadingFrameRequest(const blink::WebURL& url,
-                                    void* notify_data) override;
-  void didFailLoadingFrameRequest(const blink::WebURL& url,
-                                  void* notify_data,
-                                  const blink::WebURLError& error) override;
   bool hasSelection() const override;
   blink::WebString selectionAsText() const override;
   blink::WebString selectionAsMarkup() const override;
diff --git a/content/renderer/pepper/video_decoder_shim.cc b/content/renderer/pepper/video_decoder_shim.cc
index 84dd33a..9dab8b9 100644
--- a/content/renderer/pepper/video_decoder_shim.cc
+++ b/content/renderer/pepper/video_decoder_shim.cc
@@ -868,18 +868,22 @@
                  base::Owned(decoder_impl_.release())));
 }
 
-bool VideoDecoderShim::Initialize(
-    media::VideoCodecProfile profile,
-    media::VideoDecodeAccelerator::Client* client) {
+bool VideoDecoderShim::Initialize(const Config& vda_config, Client* client) {
   DCHECK_EQ(client, host_);
   DCHECK(RenderThreadImpl::current());
   DCHECK_EQ(state_, UNINITIALIZED);
+
+  if (vda_config.is_encrypted) {
+    NOTREACHED() << "Encrypted streams are not supported";
+    return false;
+  }
+
   media::VideoCodec codec = media::kUnknownVideoCodec;
-  if (profile <= media::H264PROFILE_MAX)
+  if (vda_config.profile <= media::H264PROFILE_MAX)
     codec = media::kCodecH264;
-  else if (profile <= media::VP8PROFILE_MAX)
+  else if (vda_config.profile <= media::VP8PROFILE_MAX)
     codec = media::kCodecVP8;
-  else if (profile <= media::VP9PROFILE_MAX)
+  else if (vda_config.profile <= media::VP9PROFILE_MAX)
     codec = media::kCodecVP9;
   DCHECK_NE(codec, media::kUnknownVideoCodec);
 
@@ -889,8 +893,9 @@
   if (!yuv_converter_->Initialize())
     return false;
 
-  media::VideoDecoderConfig config(
-      codec, profile, media::PIXEL_FORMAT_YV12, media::COLOR_SPACE_UNSPECIFIED,
+  media::VideoDecoderConfig video_decoder_config(
+      codec, vda_config.profile, media::PIXEL_FORMAT_YV12,
+      media::COLOR_SPACE_UNSPECIFIED,
       gfx::Size(32, 24),  // Small sizes that won't fail.
       gfx::Rect(32, 24), gfx::Size(32, 24),
       // TODO(bbudge): Verify extra data isn't needed.
@@ -899,8 +904,7 @@
   media_task_runner_->PostTask(
       FROM_HERE,
       base::Bind(&VideoDecoderShim::DecoderImpl::Initialize,
-                 base::Unretained(decoder_impl_.get()),
-                 config));
+                 base::Unretained(decoder_impl_.get()), video_decoder_config));
 
   state_ = DECODING;
 
diff --git a/content/renderer/pepper/video_decoder_shim.h b/content/renderer/pepper/video_decoder_shim.h
index deefdced..566a0de 100644
--- a/content/renderer/pepper/video_decoder_shim.h
+++ b/content/renderer/pepper/video_decoder_shim.h
@@ -50,8 +50,7 @@
   ~VideoDecoderShim() override;
 
   // media::VideoDecodeAccelerator implementation.
-  bool Initialize(media::VideoCodecProfile profile,
-                  media::VideoDecodeAccelerator::Client* client) override;
+  bool Initialize(const Config& config, Client* client) override;
   void Decode(const media::BitstreamBuffer& bitstream_buffer) override;
   void AssignPictureBuffers(
       const std::vector<media::PictureBuffer>& buffers) override;
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index 0db8f24e..860e3d5 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -827,6 +827,7 @@
       renderer_accessibility_(NULL),
       media_player_delegate_(NULL),
       is_using_lofi_(false),
+      is_pasting_(false),
       weak_factory_(this) {
   std::pair<RoutingIDFrameMap::iterator, bool> result =
       g_routing_id_frame_map.Get().insert(std::make_pair(routing_id_, this));
@@ -1242,6 +1243,7 @@
     IPC_MESSAGE_HANDLER(FrameMsg_DidUpdateSandboxFlags, OnDidUpdateSandboxFlags)
     IPC_MESSAGE_HANDLER(FrameMsg_SetFrameOwnerProperties,
                         OnSetFrameOwnerProperties)
+    IPC_MESSAGE_HANDLER(FrameMsg_AdvanceFocus, OnAdvanceFocus)
     IPC_MESSAGE_HANDLER(FrameMsg_SetTextTrackSettings,
                         OnTextTrackSettingsChanged)
     IPC_MESSAGE_HANDLER(FrameMsg_PostMessageEvent, OnPostMessageEvent)
@@ -1448,6 +1450,8 @@
     // Internal request, forward to WebKit.
     context_menu_node_.reset();
   }
+
+  render_view()->webview()->didCloseContextMenu();
 }
 
 void RenderFrameImpl::OnCustomContextMenuAction(
@@ -1487,6 +1491,7 @@
 
 void RenderFrameImpl::OnPaste() {
   base::AutoReset<bool> handling_select_range(&handling_select_range_, true);
+  base::AutoReset<bool> handling_paste(&is_pasting_, true);
   frame_->executeCommand(WebString::fromUTF8("Paste"), GetFocusedElement());
 }
 
@@ -1751,10 +1756,7 @@
   if (!GetRenderWidget()->ShouldHandleImeEvent())
     return;
 
-  DCHECK(!WebUserGestureIndicator::isProcessingUserGesture());
-
   ImeEventGuard guard(GetRenderWidget());
-  blink::WebScopedUserGesture gesture_indicator;
   frame_->extendSelectionAndDelete(before, after);
 }
 
@@ -1800,6 +1802,17 @@
   frame_->setFrameOwnerProperties(frame_owner_properties);
 }
 
+void RenderFrameImpl::OnAdvanceFocus(blink::WebFocusType type,
+                                     int32_t source_routing_id) {
+  RenderFrameProxy* source_frame =
+      RenderFrameProxy::FromRoutingID(source_routing_id);
+  if (!source_frame)
+    return;
+
+  render_view_->webview()->advanceFocusAcrossFrames(
+      type, source_frame->web_frame(), frame_);
+}
+
 void RenderFrameImpl::OnTextTrackSettingsChanged(
     const FrameMsg_TextTrackSettings_Params& params) {
   DCHECK(!frame_->parent());
@@ -2160,6 +2173,10 @@
   return is_using_lofi_;
 }
 
+bool RenderFrameImpl::IsPasting() const {
+  return is_pasting_;
+}
+
 // blink::WebFrameClient implementation ----------------------------------------
 
 blink::WebPlugin* RenderFrameImpl::createPlugin(
@@ -3369,6 +3386,10 @@
 
 void RenderFrameImpl::showContextMenu(const blink::WebContextMenuData& data) {
   ContextMenuParams params = ContextMenuParamsBuilder::Build(data);
+  blink::WebRect position_in_window(params.x, params.y, 0, 0);
+  GetRenderWidget()->convertViewportToWindow(&position_in_window);
+  params.x = position_in_window.x;
+  params.y = position_in_window.y;
   params.source_type = GetRenderWidget()->context_menu_source_type();
   GetRenderWidget()->OnShowHostContextMenu(&params);
   if (GetRenderWidget()->has_host_context_menu_location()) {
@@ -3723,16 +3744,6 @@
                     DidChangePerformanceTiming());
 }
 
-void RenderFrameImpl::didAbortLoading(blink::WebLocalFrame* frame) {
-  DCHECK(!frame_ || frame_ == frame);
-#if defined(ENABLE_PLUGINS)
-  if (frame != render_view_->webview()->mainFrame())
-    return;
-  PluginChannelHost::Broadcast(
-      new PluginHostMsg_DidAbortLoading(render_view_->GetRoutingID()));
-#endif
-}
-
 void RenderFrameImpl::didCreateScriptContext(blink::WebLocalFrame* frame,
                                              v8::Local<v8::Context> context,
                                              int extension_group,
diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h
index 374e09d..bae9b33 100644
--- a/content/renderer/render_frame_impl.h
+++ b/content/renderer/render_frame_impl.h
@@ -29,6 +29,7 @@
 #include "media/blink/webmediaplayer_params.h"
 #include "mojo/application/public/interfaces/service_provider.mojom.h"
 #include "mojo/application/public/interfaces/shell.mojom.h"
+#include "third_party/WebKit/public/platform/WebFocusType.h"
 #include "third_party/WebKit/public/platform/modules/app_banner/WebAppBannerClient.h"
 #include "third_party/WebKit/public/web/WebAXObject.h"
 #include "third_party/WebKit/public/web/WebDataSource.h"
@@ -392,6 +393,7 @@
   void AddMessageToConsole(ConsoleMessageLevel level,
                            const std::string& message) override;
   bool IsUsingLoFi() const override;
+  bool IsPasting() const override;
 
   // blink::WebFrameClient implementation:
   blink::WebPlugin* createPlugin(blink::WebLocalFrame* frame,
@@ -531,7 +533,6 @@
       const blink::WebURL& main_resource_url,
       const blink::WebCString& main_resource_security_info) override;
   void didChangePerformanceTiming() override;
-  void didAbortLoading(blink::WebLocalFrame* frame) override;
   void didCreateScriptContext(blink::WebLocalFrame* frame,
                               v8::Local<v8::Context> context,
                               int extension_group,
@@ -746,6 +747,7 @@
   void OnDidUpdateSandboxFlags(blink::WebSandboxFlags flags);
   void OnSetFrameOwnerProperties(
       const blink::WebFrameOwnerProperties& frame_owner_properties);
+  void OnAdvanceFocus(blink::WebFocusType type, int32_t source_routing_id);
   void OnTextTrackSettingsChanged(
       const FrameMsg_TextTrackSettings_Params& params);
   void OnPostMessageEvent(const FrameMsg_PostMessage_Params& params);
@@ -1111,6 +1113,9 @@
   // Whether or not this RenderFrame is using Lo-Fi mode.
   bool is_using_lofi_;
 
+  // Whether or not this RenderFrame is currently pasting.
+  bool is_pasting_;
+
 #if defined(ENABLE_WEBVR)
   // The VR dispatcher attached to the frame, lazily initialized.
   scoped_ptr<VRDispatcher> vr_dispatcher_;
diff --git a/content/renderer/render_frame_proxy.cc b/content/renderer/render_frame_proxy.cc
index 600d478..f753af4 100644
--- a/content/renderer/render_frame_proxy.cc
+++ b/content/renderer/render_frame_proxy.cc
@@ -444,4 +444,10 @@
   Send(new FrameHostMsg_DidChangeOpener(routing_id_, opener_routing_id));
 }
 
+void RenderFrameProxy::advanceFocus(blink::WebFocusType type,
+                                    blink::WebLocalFrame* source) {
+  int source_routing_id = RenderFrameImpl::FromWebFrame(source)->GetRoutingID();
+  Send(new FrameHostMsg_AdvanceFocus(routing_id_, type, source_routing_id));
+}
+
 }  // namespace
diff --git a/content/renderer/render_frame_proxy.h b/content/renderer/render_frame_proxy.h
index d54e15e..1e4c288 100644
--- a/content/renderer/render_frame_proxy.h
+++ b/content/renderer/render_frame_proxy.h
@@ -10,6 +10,7 @@
 #include "content/common/content_export.h"
 #include "ipc/ipc_listener.h"
 #include "ipc/ipc_sender.h"
+#include "third_party/WebKit/public/platform/WebFocusType.h"
 #include "third_party/WebKit/public/web/WebRemoteFrame.h"
 #include "third_party/WebKit/public/web/WebRemoteFrameClient.h"
 #include "url/origin.h"
@@ -132,6 +133,8 @@
   void forwardInputEvent(const blink::WebInputEvent* event) override;
   void frameRectsChanged(const blink::WebRect& frame_rect) override;
   void didChangeOpener(blink::WebFrame* opener) override;
+  void advanceFocus(blink::WebFocusType type,
+                    blink::WebLocalFrame* source) override;
 
   // IPC handlers
   void OnDidStartLoading();
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc
index 992825b..4bf3ebcf 100644
--- a/content/renderer/render_thread_impl.cc
+++ b/content/renderer/render_thread_impl.cc
@@ -148,6 +148,7 @@
 #include "third_party/WebKit/public/web/WebFrame.h"
 #include "third_party/WebKit/public/web/WebImageCache.h"
 #include "third_party/WebKit/public/web/WebKit.h"
+#include "third_party/WebKit/public/web/WebMemoryPressureListener.h"
 #include "third_party/WebKit/public/web/WebNetworkStateNotifier.h"
 #include "third_party/WebKit/public/web/WebRuntimeFeatures.h"
 #include "third_party/WebKit/public/web/WebScriptController.h"
@@ -203,7 +204,7 @@
 
 #if defined(MOJO_SHELL_CLIENT)
 #include "content/public/common/mojo_shell_connection.h"
-#include "content/renderer/render_widget_window_tree_client_factory.h"
+#include "content/renderer/mus/render_widget_window_tree_client_factory.h"
 #endif
 
 using base::ThreadRestrictions;
@@ -1854,7 +1855,7 @@
 
   // Do not call into blink if it is not initialized.
   if (blink_platform_impl_) {
-    blink::WebCache::pruneAll();
+    blink::WebMemoryPressureListener::onMemoryPressure();
 
     if (blink::mainThreadIsolate()) {
       // Trigger full v8 garbage collection on memory pressure notifications.
diff --git a/content/renderer/render_view_browsertest.cc b/content/renderer/render_view_browsertest.cc
index bcdc6afd..3e3c3364b 100644
--- a/content/renderer/render_view_browsertest.cc
+++ b/content/renderer/render_view_browsertest.cc
@@ -366,7 +366,7 @@
 
 class RenderViewImplBlinkSettingsTest : public RenderViewImplTest {
  public:
-  void DoSetUp() {
+  virtual void DoSetUp() {
     RenderViewImplTest::SetUp();
   }
 
@@ -384,6 +384,22 @@
   void SetUp() override {}
 };
 
+class RenderViewImplScaleFactorTest : public RenderViewImplBlinkSettingsTest {
+ public:
+  void DoSetUp() override {
+    RenderViewImplBlinkSettingsTest::DoSetUp();
+
+    ViewMsg_Resize_Params params;
+    params.screen_info.deviceScaleFactor = 2.f;
+    params.new_size = gfx::Size(100, 100);
+    params.physical_backing_size = gfx::Size(200, 200);
+    params.visible_viewport_size = params.new_size;
+    params.needs_resize_ack = false;
+    view()->OnResize(params);
+    ASSERT_EQ(2.f, view()->device_scale_factor_);
+  }
+};
+
 // Ensure that the main RenderFrame is deleted and cleared from the RenderView
 // after closing it.
 TEST_F(RenderViewImplTest, RenderFrameClearedAfterClose) {
@@ -479,6 +495,7 @@
     EXPECT_TRUE(render_thread_->sink().GetUniqueMessageMatching(
         ViewHostMsg_UpdateState::ID));
   }
+  ProcessPendingMessages();
 }
 
 TEST_F(RenderViewImplTest, OnNavigationHttpPost) {
@@ -1072,6 +1089,7 @@
       // message to activate IMEs.
       view()->UpdateTextInputState(
           RenderWidget::NO_SHOW_IME, RenderWidget::FROM_NON_IME);
+      ProcessPendingMessages();
       const IPC::Message* msg = render_thread_->sink().GetMessageAt(0);
       EXPECT_TRUE(msg != NULL);
       EXPECT_EQ(ViewHostMsg_TextInputStateChanged::ID, msg->type());
@@ -2471,6 +2489,29 @@
   EXPECT_TRUE(settings()->viewportEnabled());
 }
 
+TEST_F(RenderViewImplScaleFactorTest, ConverViewportToWindowWithoutZoomForDSF) {
+  DoSetUp();
+  blink::WebRect rect(20, 10, 200, 100);
+  view()->convertViewportToWindow(&rect);
+  EXPECT_EQ(20, rect.x);
+  EXPECT_EQ(10, rect.y);
+  EXPECT_EQ(200, rect.width);
+  EXPECT_EQ(100, rect.height);
+}
+
+TEST_F(RenderViewImplScaleFactorTest, ConverViewportToWindowWithZoomForDSF) {
+  base::CommandLine::ForCurrentProcess()->AppendSwitch(
+      switches::kEnableUseZoomForDSF);
+  DoSetUp();
+
+  blink::WebRect rect(20, 10, 200, 100);
+  view()->convertViewportToWindow(&rect);
+  EXPECT_EQ(10, rect.x);
+  EXPECT_EQ(5, rect.y);
+  EXPECT_EQ(100, rect.width);
+  EXPECT_EQ(50, rect.height);
+}
+
 TEST_F(DevToolsAgentTest, DevToolsResumeOnClose) {
   Attach();
   EXPECT_FALSE(IsPaused());
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc
index e71d180..a5aa817 100644
--- a/content/renderer/render_view_impl.cc
+++ b/content/renderer/render_view_impl.cc
@@ -88,7 +88,6 @@
 #include "content/renderer/mhtml_generator.h"
 #include "content/renderer/mojo_bindings_controller.h"
 #include "content/renderer/navigation_state_impl.h"
-#include "content/renderer/net_info_helper.h"
 #include "content/renderer/render_frame_impl.h"
 #include "content/renderer/render_frame_proxy.h"
 #include "content/renderer/render_process.h"
@@ -149,7 +148,6 @@
 #include "third_party/WebKit/public/web/WebLocalFrame.h"
 #include "third_party/WebKit/public/web/WebMediaPlayerAction.h"
 #include "third_party/WebKit/public/web/WebNavigationPolicy.h"
-#include "third_party/WebKit/public/web/WebNetworkStateNotifier.h"
 #include "third_party/WebKit/public/web/WebPageImportanceSignals.h"
 #include "third_party/WebKit/public/web/WebPlugin.h"
 #include "third_party/WebKit/public/web/WebPluginAction.h"
@@ -274,7 +272,6 @@
 using blink::WebView;
 using blink::WebWidget;
 using blink::WebWindowFeatures;
-using blink::WebNetworkStateNotifier;
 using blink::WebRuntimeFeatures;
 using base::Time;
 using base::TimeDelta;
@@ -989,8 +986,6 @@
   settings->setAccelerated2dCanvasMSAASampleCount(
       prefs.accelerated_2d_canvas_msaa_sample_count);
 
-  settings->setAsynchronousSpellCheckingEnabled(
-      prefs.asynchronous_spell_checking_enabled);
   settings->setUnifiedTextCheckerEnabled(prefs.unified_textchecker_enabled);
 
   // Tabs to link is not part of the settings. WebCore calls
@@ -1112,11 +1107,6 @@
   settings->setMainFrameResizesAreOrientationChanges(
       prefs.main_frame_resizes_are_orientation_changes);
 
-  WebNetworkStateNotifier::setOnLine(prefs.is_online);
-  WebNetworkStateNotifier::setWebConnection(
-      NetConnectionTypeToWebConnectionType(prefs.net_info_connection_type),
-      prefs.net_info_max_bandwidth_mbps);
-
   settings->setPinchOverlayScrollbarThickness(
       prefs.pinch_overlay_scrollbar_thickness);
   settings->setUseSolidColorScrollbars(prefs.use_solid_color_scrollbars);
@@ -1941,7 +1931,9 @@
   bool is_editable = false;
   if (!toNode.isNull() && toNode.isElementNode()) {
     WebElement element = const_cast<WebNode&>(toNode).to<WebElement>();
-    node_bounds = gfx::Rect(element.boundsInViewport());
+    blink::WebRect rect = element.boundsInViewport();
+    convertViewportToWindow(&rect);
+    node_bounds = gfx::Rect(rect);
     is_editable = element.isEditable();
   }
   Send(new ViewHostMsg_FocusedNodeChanged(routing_id_, is_editable,
@@ -2136,6 +2128,10 @@
   return renderer_preferences_.accept_languages;
 }
 
+void RenderViewImpl::convertViewportToWindow(blink::WebRect* rect) {
+  RenderWidget::convertViewportToWindow(rect);
+}
+
 void RenderViewImpl::didChangeIcon(WebLocalFrame* frame,
                                    WebIconURL::Type icon_type) {
   if (frame->parent())
diff --git a/content/renderer/render_view_impl.h b/content/renderer/render_view_impl.h
index 9ab5603..9a9d986 100644
--- a/content/renderer/render_view_impl.h
+++ b/content/renderer/render_view_impl.h
@@ -450,6 +450,8 @@
                               TopControlsState current,
                               bool animate) override;
 #endif
+  void convertViewportToWindow(blink::WebRect* rect) override;
+
   bool uses_temporary_zoom_level() const { return uses_temporary_zoom_level_; }
 
   // Please do not add your stuff randomly to the end here. If there is an
@@ -510,6 +512,7 @@
  private:
   // For unit tests.
   friend class DevToolsAgentTest;
+  friend class RenderViewImplScaleFactorTest;
   friend class RenderViewImplTest;
   friend class RenderViewTest;
   friend class RendererAccessibilityTest;
@@ -559,6 +562,8 @@
   FRIEND_TEST_ALL_PREFIXES(RenderViewImplTest, SendCandidateWindowEvents);
   FRIEND_TEST_ALL_PREFIXES(RenderViewImplTest, RenderFrameClearedAfterClose);
   FRIEND_TEST_ALL_PREFIXES(RenderViewImplTest, PaintAfterSwapOut);
+  FRIEND_TEST_ALL_PREFIXES(RenderViewImplScaleFactorTest,
+                           ConverViewportToScreenWithZoomForDSF);
 
   typedef std::map<GURL, double> HostZoomLevels;
 
diff --git a/content/renderer/render_widget.cc b/content/renderer/render_widget.cc
index be6f8cb..cb094441 100644
--- a/content/renderer/render_widget.cc
+++ b/content/renderer/render_widget.cc
@@ -96,7 +96,7 @@
 
 #if defined(MOJO_SHELL_CLIENT)
 #include "content/public/common/mojo_shell_connection.h"
-#include "content/renderer/render_widget_mus_connection.h"
+#include "content/renderer/mus/render_widget_mus_connection.h"
 #endif
 
 #include "third_party/WebKit/public/web/WebWidget.h"
@@ -246,6 +246,50 @@
   }
 }
 
+void LogPassiveLatency(int64 latency) {
+  UMA_HISTOGRAM_CUSTOM_COUNTS("Event.PassiveListeners.Latency", latency, 1,
+                              10000000, 100);
+}
+
+void LogPassiveEventListenersUma(WebInputEventResult result,
+                                 bool passive,
+                                 bool cancelable,
+                                 double event_timestamp,
+                                 const ui::LatencyInfo& latency_info) {
+  enum {
+    PASSIVE_LISTENER_UMA_ENUM_PASSIVE,
+    PASSIVE_LISTENER_UMA_ENUM_UNCANCELABLE,
+    PASSIVE_LISTENER_UMA_ENUM_SUPPRESSED,
+    PASSIVE_LISTENER_UMA_ENUM_CANCELABLE,
+    PASSIVE_LISTENER_UMA_ENUM_CANCELABLE_AND_CANCELED,
+    PASSIVE_LISTENER_UMA_ENUM_COUNT
+  };
+
+  int enum_value;
+  if (passive)
+    enum_value = PASSIVE_LISTENER_UMA_ENUM_PASSIVE;
+  else if (!cancelable)
+    enum_value = PASSIVE_LISTENER_UMA_ENUM_UNCANCELABLE;
+  else if (result == WebInputEventResult::HandledApplication)
+    enum_value = PASSIVE_LISTENER_UMA_ENUM_CANCELABLE_AND_CANCELED;
+  else if (result == WebInputEventResult::HandledSuppressed)
+    enum_value = PASSIVE_LISTENER_UMA_ENUM_SUPPRESSED;
+  else
+    enum_value = PASSIVE_LISTENER_UMA_ENUM_CANCELABLE;
+
+  UMA_HISTOGRAM_ENUMERATION("Event.PassiveListeners", enum_value,
+                            PASSIVE_LISTENER_UMA_ENUM_COUNT);
+
+  if (enum_value == PASSIVE_LISTENER_UMA_ENUM_CANCELABLE &&
+      base::TimeTicks::IsHighResolution()) {
+    base::TimeTicks now = base::TimeTicks::Now();
+    LogPassiveLatency(GetEventLatencyMicros(event_timestamp, now));
+    for (size_t i = 0; i < latency_info.coalesced_events_size(); i++)
+      LogPassiveLatency(GetEventLatencyMicros(
+          latency_info.timestamps_of_coalesced_events()[i], now));
+  }
+}
+
 }  // namespace
 
 namespace content {
@@ -1106,6 +1150,9 @@
                                       const ui::LatencyInfo& latency_info) {
   if (!input_event)
     return;
+
+  // TODO(dtapuska): Passive support not implemented yet crbug.com/489802
+  bool passive = false;
   base::AutoReset<bool> handling_input_event_resetter(&handling_input_event_,
                                                       true);
   base::AutoReset<WebInputEvent::Type> handling_event_type_resetter(
@@ -1191,12 +1238,28 @@
     prevent_default = prevent_default || WillHandleGestureEvent(gesture_event);
   }
 
-  bool processed = prevent_default;
+  WebInputEventResult processed =
+      prevent_default ? WebInputEventResult::HandledSuppressed
+                      : WebInputEventResult::NotHandled;
   if (input_event->type != WebInputEvent::Char || !suppress_next_char_events_) {
     suppress_next_char_events_ = false;
-    if (!processed && webwidget_)
-      processed = webwidget_->handleInputEvent(*input_event) !=
-                  WebInputEventResult::NotHandled;
+    if (processed == WebInputEventResult::NotHandled && webwidget_)
+      processed = webwidget_->handleInputEvent(*input_event);
+  }
+
+  // TODO(dtapuska): Use the input_event->timeStampSeconds as the start
+  // ideally this should be when the event was sent by the compositor to the
+  // renderer. crbug.com/565348
+  if (input_event->type == WebInputEvent::TouchStart ||
+      input_event->type == WebInputEvent::TouchMove ||
+      input_event->type == WebInputEvent::TouchEnd) {
+    LogPassiveEventListenersUma(
+        processed, passive,
+        static_cast<const WebTouchEvent*>(input_event)->cancelable,
+        input_event->timeStampSeconds, latency_info);
+  } else if (input_event->type == WebInputEvent::MouseWheel) {
+    LogPassiveEventListenersUma(processed, passive, !passive,
+                                input_event->timeStampSeconds, latency_info);
   }
 
   // If this RawKeyDown event corresponds to a browser keyboard shortcut and
@@ -1205,12 +1268,14 @@
   bool is_keyboard_shortcut =
       input_event->type == WebInputEvent::RawKeyDown &&
       static_cast<const WebKeyboardEvent*>(input_event)->isBrowserShortcut;
-  if (!processed && is_keyboard_shortcut)
+  if (processed == WebInputEventResult::NotHandled && is_keyboard_shortcut)
     suppress_next_char_events_ = true;
 
-  InputEventAckState ack_result = processed ?
-      INPUT_EVENT_ACK_STATE_CONSUMED : INPUT_EVENT_ACK_STATE_NOT_CONSUMED;
-  if (!processed &&  input_event->type == WebInputEvent::TouchStart) {
+  InputEventAckState ack_result = processed == WebInputEventResult::NotHandled
+                                      ? INPUT_EVENT_ACK_STATE_NOT_CONSUMED
+                                      : INPUT_EVENT_ACK_STATE_CONSUMED;
+  if (processed == WebInputEventResult::NotHandled &&
+      input_event->type == WebInputEvent::TouchStart) {
     const WebTouchEvent& touch_event =
         *static_cast<const WebTouchEvent*>(input_event);
     // Hit-test for all the pressed touch points. If there is a touch-handler
@@ -1234,7 +1299,7 @@
         static_cast<const WebMouseWheelEvent&>(*input_event),
         event_overscroll ? event_overscroll->latest_overscroll_delta
                          : gfx::Vector2dF(),
-        processed);
+        processed != WebInputEventResult::NotHandled);
   }
 
   bool frame_pending = compositor_ && compositor_->BeginMainFrameRequested();
@@ -1301,13 +1366,16 @@
 #if defined(OS_ANDROID)
   // Allow the IME to be shown when the focus changes as a consequence
   // of a processed touch end event.
-  if (input_event->type == WebInputEvent::TouchEnd && processed)
+  if (input_event->type == WebInputEvent::TouchEnd &&
+      processed != WebInputEventResult::NotHandled) {
     UpdateTextInputState(SHOW_IME_IF_NEEDED, FROM_NON_IME);
+  }
 #elif defined(USE_AURA)
   // Show the virtual keyboard if enabled and a user gesture triggers a focus
   // change.
-  if (processed && (input_event->type == WebInputEvent::TouchEnd ||
-                    input_event->type == WebInputEvent::MouseUp)) {
+  if (processed != WebInputEventResult::NotHandled &&
+      (input_event->type == WebInputEvent::TouchEnd ||
+       input_event->type == WebInputEvent::MouseUp)) {
     UpdateTextInputState(SHOW_IME_IF_NEEDED, FROM_IME);
   }
 #endif
@@ -1321,8 +1389,9 @@
 // virtual keyboard.
 #if !defined(OS_ANDROID)
   // Virtual keyboard is not supported, so react to focus change immediately.
-  if (processed && (input_event->type == WebInputEvent::TouchEnd ||
-                    input_event->type == WebInputEvent::MouseUp)) {
+  if (processed != WebInputEventResult::NotHandled &&
+      (input_event->type == WebInputEvent::TouchEnd ||
+       input_event->type == WebInputEvent::MouseUp)) {
     FocusChangeComplete();
   }
 #endif
@@ -1778,6 +1847,20 @@
   OnShowImeIfNeeded();
 }
 
+void RenderWidget::convertViewportToWindow(blink::WebRect* rect) {
+  if (IsUseZoomForDSFEnabled()) {
+    float reverse = 1 / device_scale_factor_;
+    // TODO(oshima): We may wait to allow pixel precision here as the the
+    // anchor element can be placed at half pixel.
+    gfx::Rect window_rect =
+        gfx::ScaleToEnclosedRect(gfx::Rect(*rect), reverse);
+    rect->x = window_rect.x();
+    rect->y = window_rect.y();
+    rect->width = window_rect.width();
+    rect->height = window_rect.height();
+  }
+}
+
 void RenderWidget::OnShowImeIfNeeded() {
 #if defined(OS_ANDROID) || defined(USE_AURA)
   UpdateTextInputState(SHOW_IME_IF_NEEDED, FROM_NON_IME);
diff --git a/content/renderer/render_widget.h b/content/renderer/render_widget.h
index 1b2cbff..f9b2d4f1 100644
--- a/content/renderer/render_widget.h
+++ b/content/renderer/render_widget.h
@@ -197,6 +197,10 @@
                      const blink::WebFloatSize& velocity) override;
   void showImeIfNeeded() override;
 
+  // Converts the |rect| from Viewport coordinates to Window coordinates.
+  // See RenderView::convertViewportToWindow for more details.
+  void convertViewportToWindow(blink::WebRect* rect);
+
 #if defined(OS_ANDROID)
   // Notifies that a tap was not consumed, so showing a UI for the unhandled
   // tap may be needed.
diff --git a/content/renderer/render_widget_mus_connection.cc b/content/renderer/render_widget_mus_connection.cc
deleted file mode 100644
index e0e81a5..0000000
--- a/content/renderer/render_widget_mus_connection.cc
+++ /dev/null
@@ -1,99 +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.
-
-#include "content/renderer/render_widget_mus_connection.h"
-
-#include <map>
-
-#include "base/lazy_instance.h"
-#include "components/mus/public/cpp/context_provider.h"
-#include "components/mus/public/cpp/output_surface.h"
-#include "components/mus/public/interfaces/command_buffer.mojom.h"
-#include "components/mus/public/interfaces/compositor_frame.mojom.h"
-#include "components/mus/public/interfaces/gpu.mojom.h"
-#include "components/mus/public/interfaces/window_tree.mojom.h"
-#include "content/public/common/mojo_shell_connection.h"
-#include "mojo/application/public/cpp/application_impl.h"
-#include "mojo/converters/geometry/geometry_type_converters.h"
-#include "mojo/converters/surfaces/surfaces_utils.h"
-
-namespace content {
-
-namespace {
-
-typedef std::map<int, RenderWidgetMusConnection*> ConnectionMap;
-base::LazyInstance<ConnectionMap>::Leaky g_connections =
-    LAZY_INSTANCE_INITIALIZER;
-}
-
-RenderWidgetMusConnection::RenderWidgetMusConnection(int routing_id)
-    : routing_id_(routing_id), root_(nullptr) {
-  DCHECK(routing_id);
-}
-
-RenderWidgetMusConnection::~RenderWidgetMusConnection() {}
-
-void RenderWidgetMusConnection::Bind(
-    mojo::InterfaceRequest<mus::mojom::WindowTreeClient> request) {
-  DCHECK(!root_);
-  mus::WindowTreeConnection::Create(
-      this, request.Pass(),
-      mus::WindowTreeConnection::CreateType::DONT_WAIT_FOR_EMBED);
-}
-
-scoped_ptr<cc::OutputSurface> RenderWidgetMusConnection::CreateOutputSurface() {
-  DCHECK(!window_surface_binding_);
-  mus::mojom::GpuPtr gpu_service;
-  MojoShellConnection::Get()->GetApplication()->ConnectToService("mojo:mus",
-                                                                 &gpu_service);
-  mus::mojom::CommandBufferPtr cb;
-  gpu_service->CreateOffscreenGLES2Context(GetProxy(&cb));
-  scoped_refptr<cc::ContextProvider> context_provider(
-      new mus::ContextProvider(cb.PassInterface().PassHandle()));
-  scoped_ptr<cc::OutputSurface> output_surface(new mus::OutputSurface(
-      context_provider, mus::WindowSurface::Create(&window_surface_binding_)));
-  if (root_) {
-    root_->AttachSurface(mus::mojom::SURFACE_TYPE_DEFAULT,
-                         window_surface_binding_.Pass());
-  }
-  return output_surface.Pass();
-}
-
-// static
-RenderWidgetMusConnection* RenderWidgetMusConnection::GetOrCreate(
-    int routing_id) {
-  auto it = g_connections.Get().find(routing_id);
-  if (it != g_connections.Get().end())
-    return it->second;
-
-  RenderWidgetMusConnection* connection =
-      new RenderWidgetMusConnection(routing_id);
-  g_connections.Get().insert(std::make_pair(routing_id, connection));
-  return connection;
-}
-
-void RenderWidgetMusConnection::OnConnectionLost(
-    mus::WindowTreeConnection* connection) {
-  g_connections.Get().erase(routing_id_);
-  delete this;
-}
-
-void RenderWidgetMusConnection::OnEmbed(mus::Window* root) {
-  root_ = root;
-  root_->AddObserver(this);
-  if (window_surface_binding_) {
-    root->AttachSurface(mus::mojom::SURFACE_TYPE_DEFAULT,
-                        window_surface_binding_.Pass());
-  }
-}
-
-void RenderWidgetMusConnection::OnUnembed() {}
-
-void RenderWidgetMusConnection::OnWindowBoundsChanged(
-    mus::Window* window,
-    const gfx::Rect& old_bounds,
-    const gfx::Rect& new_bounds) {
-}
-
-}  // namespace content
diff --git a/content/renderer/render_widget_mus_connection.h b/content/renderer/render_widget_mus_connection.h
deleted file mode 100644
index b3f4549..0000000
--- a/content/renderer/render_widget_mus_connection.h
+++ /dev/null
@@ -1,53 +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.
-
-#ifndef CONTENT_RENDERER_RENDER_WIDGET_MUS_CONNECTION_H_
-#define CONTENT_RENDERER_RENDER_WIDGET_MUS_CONNECTION_H_
-
-#include "base/macros.h"
-#include "cc/output/output_surface.h"
-#include "components/mus/public/cpp/window.h"
-#include "components/mus/public/cpp/window_observer.h"
-#include "components/mus/public/cpp/window_surface.h"
-#include "components/mus/public/cpp/window_tree_connection.h"
-#include "components/mus/public/cpp/window_tree_delegate.h"
-#include "mojo/public/cpp/bindings/binding.h"
-
-namespace content {
-
-class RenderWidgetMusConnection : public mus::WindowTreeDelegate,
-                                  public mus::WindowObserver {
- public:
-  explicit RenderWidgetMusConnection(int routing_id);
-  ~RenderWidgetMusConnection() override;
-
-  // Connect to a WindowTreeClient request.
-  void Bind(mojo::InterfaceRequest<mus::mojom::WindowTreeClient> request);
-
-  // Create a cc output surface.
-  scoped_ptr<cc::OutputSurface> CreateOutputSurface();
-
-  // Get the connection from a routing_id, if the connection doesn't exist,
-  // a new connection will be created.
-  static RenderWidgetMusConnection* GetOrCreate(int routing_id);
-
- private:
-  // WindowTreeDelegate implementation:
-  void OnConnectionLost(mus::WindowTreeConnection* connection) override;
-  void OnEmbed(mus::Window* root) override;
-  void OnUnembed() override;
-  void OnWindowBoundsChanged(mus::Window* window,
-                             const gfx::Rect& old_bounds,
-                             const gfx::Rect& new_bounds) override;
-
-  const int routing_id_;
-  mus::Window* root_;
-  scoped_ptr<mus::WindowSurfaceBinding> window_surface_binding_;
-
-  DISALLOW_COPY_AND_ASSIGN(RenderWidgetMusConnection);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_RENDERER_RENDER_WIDGET_MUS_CONNECTION_H_
diff --git a/content/renderer/render_widget_window_tree_client_factory.h b/content/renderer/render_widget_window_tree_client_factory.h
deleted file mode 100644
index 09eb36b98..0000000
--- a/content/renderer/render_widget_window_tree_client_factory.h
+++ /dev/null
@@ -1,14 +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.
-
-#ifndef CONTENT_RENDERER_RENDER_WIDGET_WINDOW_TREE_CLIENT_FACTORY_H_
-#define CONTENT_RENDERER_RENDER_WIDGET_WINDOW_TREE_CLIENT_FACTORY_H_
-
-namespace content {
-
-void CreateRenderWidgetWindowTreeClientFactory();
-
-}  // namespace content
-
-#endif  // CONTENT_RENDERER_RENDER_WIDGET_WINDOW_TREE_CLIENT_FACTORY_H_
diff --git a/content/renderer/renderer_main_platform_delegate_win.cc b/content/renderer/renderer_main_platform_delegate_win.cc
index aae8ea1..675961d 100644
--- a/content/renderer/renderer_main_platform_delegate_win.cc
+++ b/content/renderer/renderer_main_platform_delegate_win.cc
@@ -87,9 +87,6 @@
     // Cause advapi32 to load before the sandbox is turned on.
     unsigned int dummy_rand;
     rand_s(&dummy_rand);
-    // Warm up language subsystems before the sandbox is turned on.
-    ::GetUserDefaultLangID();
-    ::GetUserDefaultLCID();
 
     target_services->LowerToken();
     return true;
diff --git a/content/shell/android/javatests/src/org/chromium/content_shell_apk/ContentShellTestBase.java b/content/shell/android/javatests/src/org/chromium/content_shell_apk/ContentShellTestBase.java
index f002c553..d5e54857 100644
--- a/content/shell/android/javatests/src/org/chromium/content_shell_apk/ContentShellTestBase.java
+++ b/content/shell/android/javatests/src/org/chromium/content_shell_apk/ContentShellTestBase.java
@@ -78,7 +78,7 @@
     protected void startActivityWithTestUrl(String url) throws Throwable {
         launchContentShellWithUrl(UrlUtils.getIsolatedTestFileUrl(url));
         assertNotNull(getActivity());
-        assertTrue(waitForActiveShellToBeDoneLoading());
+        waitForActiveShellToBeDoneLoading();
         assertEquals(UrlUtils.getIsolatedTestFileUrl(url),
                 getContentViewCore().getWebContents().getUrl());
     }
@@ -102,14 +102,13 @@
      * WAIT_FOR_ACTIVE_SHELL_LOADING_TIMEOUT milliseconds and it shouldn't be used for long
      * loading pages. Instead it should be used more for test initialization. The proper way
      * to wait is to use a TestCallbackHelperContainer after the initial load is completed.
-     * @return Whether or not the Shell was actually finished loading.
      * @throws InterruptedException
      */
-    protected boolean waitForActiveShellToBeDoneLoading() throws InterruptedException {
+    protected void waitForActiveShellToBeDoneLoading() throws InterruptedException {
         final ContentShellActivity activity = getActivity();
 
         // Wait for the Content Shell to be initialized.
-        return CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 Shell shell = activity.getActiveShell();
@@ -117,9 +116,19 @@
                 // The first is that we've just created a Shell and it isn't
                 // loading because it has no URL set yet.  The second is that
                 // we've set a URL and it actually is loading.
-                if (shell == null) return false;
-                return !shell.isLoading() && !TextUtils.isEmpty(shell.getContentViewCore()
-                        .getWebContents().getUrl());
+                if (shell == null) {
+                    updateFailureReason("Shell is null.");
+                    return false;
+                }
+                if (shell.isLoading()) {
+                    updateFailureReason("Shell is still loading.");
+                    return false;
+                }
+                if (TextUtils.isEmpty(shell.getContentViewCore().getWebContents().getUrl())) {
+                    updateFailureReason("Shell's URL is empty or null.");
+                    return false;
+                }
+                return true;
             }
         }, WAIT_FOR_ACTIVE_SHELL_LOADING_TIMEOUT, CriteriaHelper.DEFAULT_POLLING_INTERVAL);
     }
@@ -191,12 +200,12 @@
      */
     protected void assertWaitForPageScaleFactorMatch(final float expectedScale)
             throws InterruptedException {
-        assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
+        CriteriaHelper.pollForCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 return getContentViewCore().getScale() == expectedScale;
             }
-        }));
+        });
     }
 
     /**
diff --git a/content/shell/browser/layout_test/layout_test_bluetooth_adapter_provider.cc b/content/shell/browser/layout_test/layout_test_bluetooth_adapter_provider.cc
index d8f2d76..32f7d6368 100644
--- a/content/shell/browser/layout_test/layout_test_bluetooth_adapter_provider.cc
+++ b/content/shell/browser/layout_test/layout_test_bluetooth_adapter_provider.cc
@@ -216,7 +216,7 @@
   // matching the address provided if the device was added to the mock.
   ON_CALL(*adapter, GetDevice(_)).WillByDefault(GetMockDevice(adapter.get()));
 
-  return adapter.Pass();
+  return adapter;
 }
 
 // static
@@ -225,7 +225,7 @@
   scoped_refptr<NiceMockBluetoothAdapter> adapter(GetBaseAdapter());
   ON_CALL(*adapter, IsPresent()).WillByDefault(Return(true));
 
-  return adapter.Pass();
+  return adapter;
 }
 
 // static
@@ -234,7 +234,7 @@
   scoped_refptr<NiceMockBluetoothAdapter> adapter(GetBaseAdapter());
   ON_CALL(*adapter, IsPresent()).WillByDefault(Return(false));
 
-  return adapter.Pass();
+  return adapter;
 }
 
 // static
@@ -243,7 +243,7 @@
   scoped_refptr<NiceMockBluetoothAdapter> adapter(GetPresentAdapter());
   ON_CALL(*adapter, IsPowered()).WillByDefault(Return(true));
 
-  return adapter.Pass();
+  return adapter;
 }
 
 // static
@@ -252,7 +252,7 @@
   scoped_refptr<NiceMockBluetoothAdapter> adapter(GetPresentAdapter());
   ON_CALL(*adapter, IsPowered()).WillByDefault(Return(false));
 
-  return adapter.Pass();
+  return adapter;
 }
 
 // static
@@ -279,7 +279,7 @@
   // We need to add a device otherwise requestDevice would reject.
   adapter->AddMockDevice(GetBatteryDevice(adapter.get()));
 
-  return adapter.Pass();
+  return adapter;
 }
 
 // static
@@ -290,7 +290,7 @@
   ON_CALL(*adapter, StartDiscoverySessionWithFilterRaw(_, _, _))
       .WillByDefault(RunCallback<2 /* error_callback */>());
 
-  return adapter.Pass();
+  return adapter;
 }
 
 // static
@@ -302,7 +302,7 @@
       .WillByDefault(RunCallbackWithResult<1 /* success_callback */>(
           []() { return GetDiscoverySession(); }));
 
-  return adapter.Pass();
+  return adapter;
 }
 
 // static
@@ -342,7 +342,7 @@
   adapter->AddMockDevice(GetHeartRateDevice(adapter.get()));
   adapter->AddMockDevice(GetGlucoseDevice(adapter.get()));
 
-  return adapter.Pass();
+  return adapter;
 }
 
 // static
@@ -352,7 +352,7 @@
 
   adapter->AddMockDevice(GetBaseDevice(adapter.get(), "❤❤❤❤❤❤❤❤❤"));
 
-  return adapter.Pass();
+  return adapter;
 }
 
 // Adds a device to |adapter| and notifies all observers about that new device.
@@ -396,7 +396,7 @@
 
   adapter->AddMockDevice(GetHeartRateDevice(adapter.get()));
 
-  return adapter.Pass();
+  return adapter;
 }
 
 // static
@@ -417,7 +417,7 @@
   device->AddMockService(heart_rate.Pass());
   adapter->AddMockDevice(device.Pass());
 
-  return adapter.Pass();
+  return adapter;
 }
 
 // static
@@ -462,7 +462,7 @@
 
   adapter->AddMockDevice(device.Pass());
 
-  return adapter.Pass();
+  return adapter;
 }
 
 // static
@@ -492,7 +492,7 @@
         adapter.get(), static_cast<BluetoothDevice::ConnectErrorCode>(error)));
   }
 
-  return adapter.Pass();
+  return adapter;
 }
 
 // static
@@ -521,7 +521,7 @@
   device->AddMockService(service.Pass());
   adapter->AddMockDevice(device.Pass());
 
-  return adapter.Pass();
+  return adapter;
 }
 
 // Discovery Sessions
@@ -535,7 +535,7 @@
   ON_CALL(*discovery_session, Stop(_, _))
       .WillByDefault(RunCallback<0 /* success_callback */>());
 
-  return discovery_session.Pass();
+  return discovery_session;
 }
 
 // Devices
@@ -573,7 +573,7 @@
   ON_CALL(*device, GetProductID()).WillByDefault(Return(1));
   ON_CALL(*device, GetDeviceID()).WillByDefault(Return(2));
 
-  return device.Pass();
+  return device;
 }
 
 // static
@@ -619,7 +619,7 @@
                 adapter, device_ptr->GetAddress()));
           }));
 
-  return device.Pass();
+  return device;
 }
 
 // static
@@ -637,7 +637,7 @@
   ON_CALL(*device, CreateGattConnection(_, _))
       .WillByDefault(RunCallback<1 /* error_callback */>(error_code));
 
-  return device.Pass();
+  return device;
 }
 
 // static
@@ -670,7 +670,7 @@
       .WillByDefault(Invoke(service.get(),
                             &MockBluetoothGattService::GetMockCharacteristic));
 
-  return service.Pass();
+  return service;
 }
 
 // static
@@ -731,7 +731,7 @@
             notify_session->StartTestNotifications(adapter, measurement_ptr,
                                                    rate);
 
-            return notify_session.Pass();
+            return notify_session;
           }));
 
   // Body Sensor Location Characteristic
@@ -800,7 +800,7 @@
   ON_CALL(*characteristic, StartNotifySession(_, _))
       .WillByDefault(RunCallback<1 /* error_callback */>(error_code));
 
-  return characteristic.Pass();
+  return characteristic;
 }
 
 // Notify sessions
@@ -819,7 +819,7 @@
               &MockBluetoothGattNotifySession::StopTestNotifications),
           RunCallback<0>()));
 
-  return session.Pass();
+  return session;
 }
 
 // Helper functions
diff --git a/content/shell/renderer/layout_test/blink_test_helpers.cc b/content/shell/renderer/layout_test/blink_test_helpers.cc
index 97b2b8a..8039179 100644
--- a/content/shell/renderer/layout_test/blink_test_helpers.cc
+++ b/content/shell/renderer/layout_test/blink_test_helpers.cc
@@ -41,8 +41,6 @@
       from.allow_display_of_insecure_content;
   to->allow_running_insecure_content = from.allow_running_of_insecure_content;
   to->should_respect_image_orientation = from.should_respect_image_orientation;
-  to->asynchronous_spell_checking_enabled =
-      from.asynchronous_spell_checking_enabled;
   to->allow_file_access_from_file_urls = from.allow_file_access_from_file_urls;
   to->javascript_can_open_windows_automatically =
       from.java_script_can_open_windows_automatically;
@@ -98,7 +96,6 @@
   prefs->sans_serif_font_family_map[kCommonScript] =
       base::ASCIIToUTF16("Helvetica");
   prefs->minimum_logical_font_size = 9;
-  prefs->asynchronous_spell_checking_enabled = false;
   prefs->accelerated_2d_canvas_enabled =
       command_line.HasSwitch(switches::kEnableAccelerated2DCanvas);
   prefs->mock_scrollbars_enabled = false;
diff --git a/content/shell/tools/plugin/PluginTest.cpp b/content/shell/tools/plugin/PluginTest.cpp
index d0a56c71..fa95d891 100644
--- a/content/shell/tools/plugin/PluginTest.cpp
+++ b/content/shell/tools/plugin/PluginTest.cpp
@@ -135,16 +135,6 @@
 
 // NPN functions.
 
-NPError PluginTest::NPN_GetURL(const char* url, const char* target) {
-  return browser->geturl(m_npp, url, target);
-}
-
-NPError PluginTest::NPN_GetURLNotify(const char* url,
-                                     const char* target,
-                                     void* notifyData) {
-  return browser->geturlnotify(m_npp, url, target, notifyData);
-}
-
 NPError PluginTest::NPN_GetValue(NPNVariable variable, void* value) {
   return browser->getvalue(m_npp, variable, value);
 }
diff --git a/content/shell/tools/plugin/PluginTest.h b/content/shell/tools/plugin/PluginTest.h
index 82093ae3..5df0620 100644
--- a/content/shell/tools/plugin/PluginTest.h
+++ b/content/shell/tools/plugin/PluginTest.h
@@ -98,10 +98,6 @@
   virtual NPError NPP_SetValue(NPNVariable, void* value);
 
   // NPN functions.
-  NPError NPN_GetURL(const char* url, const char* target);
-  NPError NPN_GetURLNotify(const char* url,
-                           const char* target,
-                           void* notifyData);
   NPError NPN_GetValue(NPNVariable, void* value);
   void NPN_InvalidateRect(NPRect* invalidRect);
   bool NPN_Invoke(NPObject*,
diff --git a/content/shell/tools/plugin/Tests/DocumentOpenInDestroyStream.cpp b/content/shell/tools/plugin/Tests/DocumentOpenInDestroyStream.cpp
deleted file mode 100644
index b4b2e8f..0000000
--- a/content/shell/tools/plugin/Tests/DocumentOpenInDestroyStream.cpp
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-/*
- * Copyright (C) 2010 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "PluginTest.h"
-
-using namespace std;
-
-extern bool testDocumentOpen(NPP npp);
-
-// Call document.open from NPP_DestroyStream.
-
-class DocumentOpenInDestroyStream : public PluginTest {
-public:
-    DocumentOpenInDestroyStream(NPP npp, const string& identifier)
-        : PluginTest(npp, identifier)
-        , m_shouldOpen(true)
-    {
-    }
-
-private:
- NPError NPP_DestroyStream(NPStream*, NPReason) override {
-        if (m_shouldOpen) {
-            testDocumentOpen(m_npp);
-            m_shouldOpen = false;
-        }
-
-        return NPERR_NO_ERROR;
-    }
-
-    bool m_shouldOpen;
-};
-
-static PluginTest::Register<DocumentOpenInDestroyStream> documentOpenInDestroyStream("document-open-in-destroy-stream");
diff --git a/content/shell/tools/plugin/Tests/GetURLNotifyWithURLThatFailsToLoad.cpp b/content/shell/tools/plugin/Tests/GetURLNotifyWithURLThatFailsToLoad.cpp
deleted file mode 100644
index cfbc2cd..0000000
--- a/content/shell/tools/plugin/Tests/GetURLNotifyWithURLThatFailsToLoad.cpp
+++ /dev/null
@@ -1,80 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-/*
- * Copyright (C) 2011 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "PluginTest.h"
-
-#include <string.h>
-
-using namespace std;
-
-// From NPP_New, call NPN_GetURLNotify with a URL that fails to load (NPP_NewStream won't be called).
-// The plugin should still get a NPP_URLNotify indicating that the load failed.
-static const char *urlThatFailsToLoad = "foo://bar/";
-
-class GetURLNotifyWithURLThatFailsToLoad : public PluginTest {
-public:
-    GetURLNotifyWithURLThatFailsToLoad(NPP npp, const string& identifier)
-        : PluginTest(npp, identifier)
-    {
-    }
-
-private:
- NPError NPP_New(NPMIMEType pluginType,
-                 uint16_t mode,
-                 int16_t argc,
-                 char* argn[],
-                 char* argv[],
-                 NPSavedData* saved) override {
-        NPN_GetURLNotify(urlThatFailsToLoad, 0, reinterpret_cast<void*>(0x12345678));
-        return NPERR_NO_ERROR;
-    }
-
-    bool NPP_URLNotify(const char* url,
-                       NPReason reason,
-                       void* notifyData) override {
-        bool didFail = false;
-
-        if (strcmp(url, urlThatFailsToLoad))
-            didFail = true;
-
-        if (reason != NPRES_NETWORK_ERR)
-            didFail = true;
-
-        if (notifyData != reinterpret_cast<void*>(0x12345678))
-            didFail = true;
-
-        if (!didFail)
-            executeScript("testSucceeded()");
-        else
-            executeScript("notifyDone()");
-        return true;
-    }
-};
-
-static PluginTest::Register<GetURLNotifyWithURLThatFailsToLoad> getURLWithJavaScriptURLDestroyingPlugin("get-url-notify-with-url-that-fails-to-load");
diff --git a/content/shell/tools/plugin/Tests/GetURLWithJavaScriptURL.cpp b/content/shell/tools/plugin/Tests/GetURLWithJavaScriptURL.cpp
deleted file mode 100644
index 336a370..0000000
--- a/content/shell/tools/plugin/Tests/GetURLWithJavaScriptURL.cpp
+++ /dev/null
@@ -1,122 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-/*
- * Copyright (C) 2011 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "PluginTest.h"
-
-#include <string.h>
-#include <vector>
-
-using namespace std;
-
-const char *javaScriptURL = "javascript:'Hello, ' + 'World!'";
-const char *javaScriptResult = "Hello, World!";
-
-// Test that evaluating a javascript: URL will send a stream with the result of the evaluation.
-// Test that evaluating JavaScript using NPN_GetURL will a stream with result of the evaluation.
-class GetURLWithJavaScriptURL : public PluginTest {
-public:
-    GetURLWithJavaScriptURL(NPP npp, const string& identifier)
-        : PluginTest(npp, identifier)
-        , m_didFail(false)
-    {
-    }
-
-private:
- NPError NPP_New(NPMIMEType pluginType,
-                 uint16_t mode,
-                 int16_t argc,
-                 char* argn[],
-                 char* argv[],
-                 NPSavedData* saved) override {
-        NPN_GetURL(javaScriptURL, 0);
-        return NPERR_NO_ERROR;
-    }
-
-    NPError NPP_NewStream(NPMIMEType type,
-                          NPStream* stream,
-                          NPBool seekable,
-                          uint16_t* stype) override {
-        stream->pdata = this;
-
-        if (strcmp(stream->url, javaScriptURL))
-            m_didFail = true;
-
-        if (stream->end != strlen(javaScriptResult))
-            m_didFail = true;
-
-        *stype = NP_NORMAL;
-        return NPERR_NO_ERROR;
-    }
-
-    NPError NPP_DestroyStream(NPStream* stream, NPReason reason) override {
-        if (stream->pdata != this)
-            m_didFail = true;
-
-        if (reason != NPRES_DONE)
-            m_didFail = true;
-
-        if (m_data.size() != stream->end)
-            m_didFail = true;
-
-        m_data.push_back('\0');
-
-        if (strcmp(&m_data[0], javaScriptResult))
-            m_didFail = true;
-
-        if (!m_didFail)
-            executeScript("testSucceeded()");
-        else
-            executeScript("notifyDone()");
-
-        return NPERR_NO_ERROR;
-    }
-
-    int32_t NPP_WriteReady(NPStream* stream) override {
-        if (stream->pdata != this)
-            m_didFail = true;
-
-        return 2;
-    }
-
-    int32_t NPP_Write(NPStream* stream,
-                      int32_t offset,
-                      int32_t len,
-                      void* buffer) override {
-        if (stream->pdata != this)
-            m_didFail = true;
-
-        m_data.insert(m_data.end(), static_cast<char*>(buffer), static_cast<char*>(buffer) + len);
-        return len;
-    }
-
-    vector<char> m_data;
-    bool m_didFail;
-};
-
-static PluginTest::Register<GetURLWithJavaScriptURL> getURLWithJavaScriptURLDestroyingPlugin("get-url-with-javascript-url");
diff --git a/content/shell/tools/plugin/Tests/GetURLWithJavaScriptURLDestroyingPlugin.cpp b/content/shell/tools/plugin/Tests/GetURLWithJavaScriptURLDestroyingPlugin.cpp
deleted file mode 100644
index 4e7470f..0000000
--- a/content/shell/tools/plugin/Tests/GetURLWithJavaScriptURLDestroyingPlugin.cpp
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-/*
- * Copyright (C) 2011 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "PluginTest.h"
-
-using namespace std;
-
-// From NPP_New, call NPN_GetURL to evaluate JavaScript that destroys the plugin.
-
-class GetURLWithJavaScriptURLDestroyingPlugin : public PluginTest {
-public:
-    GetURLWithJavaScriptURLDestroyingPlugin(NPP npp, const string& identifier)
-        : PluginTest(npp, identifier)
-    {
-    }
-
-private:
- NPError NPP_New(NPMIMEType pluginType,
-                 uint16_t mode,
-                 int16_t argc,
-                 char* argn[],
-                 char* argv[],
-                 NPSavedData* saved) override {
-        NPN_GetURL("javascript:removePlugin()", 0);
-        return NPERR_NO_ERROR;
-    }
-};
-
-static PluginTest::Register<GetURLWithJavaScriptURLDestroyingPlugin> getURLWithJavaScriptURLDestroyingPlugin("get-url-with-javascript-url-destroying-plugin");
diff --git a/content/test/ct/OWNERS b/content/test/ct/OWNERS
new file mode 100644
index 0000000..ba6979dc
--- /dev/null
+++ b/content/test/ct/OWNERS
@@ -0,0 +1,4 @@
+rmistry@chromium.org
+benjaminwagner@chromium.org
+borenet@chromium.org
+jcgregorio@chromium.org
diff --git a/content/test/ct/run_ct_dm.py b/content/test/ct/run_ct_dm.py
index 35cf3db..3b1e57e 100755
--- a/content/test/ct/run_ct_dm.py
+++ b/content/test/ct/run_ct_dm.py
@@ -13,8 +13,10 @@
 
 PARENT_DIR = os.path.dirname(os.path.realpath(__file__))
 
-SKIA_SRC_DIR = os.path.normpath(os.path.join(
-    PARENT_DIR, os.pardir, os.pardir, os.pardir, os.pardir, 'skia'))
+REPOS_BASE_DIR = os.path.normpath(os.path.join(
+    PARENT_DIR, os.pardir, os.pardir, os.pardir, os.pardir))
+
+SKIA_SRC_DIR = os.path.join(REPOS_BASE_DIR, 'skia')
 
 
 def main():
@@ -24,7 +26,7 @@
   args = parser.parse_args()
 
   dm_path = os.path.join(SKIA_SRC_DIR, 'out', 'Debug', 'dm')
-  skps_dir = os.path.join(PARENT_DIR, 'slave%d' % args.slave_num, 'skps')
+  skps_dir = os.path.join(REPOS_BASE_DIR, 'skps', 'slave%d' % args.slave_num)
   resource_path = os.path.join(SKIA_SRC_DIR, 'resources')
 
   # TODO(rmistry): Double check the below DM configuration with mtklein@. We
diff --git a/content/test/data/accessibility/aria/aria-math-expected-mac.txt b/content/test/data/accessibility/aria/aria-math-expected-mac.txt
index 70676613..af70c5b 100644
--- a/content/test/data/accessibility/aria/aria-math-expected-mac.txt
+++ b/content/test/data/accessibility/aria/aria-math-expected-mac.txt
@@ -1,3 +1,2 @@
 AXWebArea AXRoleDescription='HTML content'
 ++AXGroup AXSubrole=AXDocumentMath AXRoleDescription='math'
-++++AXStaticText AXRoleDescription='text' AXValue='ARIA role math.'
diff --git a/content/test/data/accessibility/aria/aria-math-expected-win.txt b/content/test/data/accessibility/aria/aria-math-expected-win.txt
index eb7d71c..41bb7b47 100644
--- a/content/test/data/accessibility/aria/aria-math-expected-win.txt
+++ b/content/test/data/accessibility/aria/aria-math-expected-win.txt
@@ -1,3 +1,2 @@
 ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE
 ++ROLE_SYSTEM_EQUATION xml-roles:math
-++++ROLE_SYSTEM_STATICTEXT name='ARIA role math.'
diff --git a/content/test/data/accessibility/aria/aria-searchbox-expected-mac.txt b/content/test/data/accessibility/aria/aria-searchbox-expected-mac.txt
index ad6b005..fe4bf976 100644
--- a/content/test/data/accessibility/aria/aria-searchbox-expected-mac.txt
+++ b/content/test/data/accessibility/aria/aria-searchbox-expected-mac.txt
@@ -1,3 +1,2 @@
 AXWebArea AXRoleDescription='HTML content'
 ++AXTextField AXSubrole=AXSearchField AXRoleDescription='search text field' AXValue='ARIA role searchbox.'
-++++AXStaticText AXRoleDescription='text' AXValue='ARIA role searchbox.'
diff --git a/content/test/data/accessibility/aria/aria-searchbox-expected-win.txt b/content/test/data/accessibility/aria/aria-searchbox-expected-win.txt
index 49831153..1b9c772 100644
--- a/content/test/data/accessibility/aria/aria-searchbox-expected-win.txt
+++ b/content/test/data/accessibility/aria/aria-searchbox-expected-win.txt
@@ -1,3 +1,2 @@
 ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE ia2_hypertext='<obj0>' n_selections=0
 ++ROLE_SYSTEM_TEXT FOCUSABLE xml-roles:searchbox ia2_hypertext='ARIA role searchbox.' caret_offset=0 n_selections=0
-++++ROLE_SYSTEM_STATICTEXT name='ARIA role searchbox.' ia2_hypertext='ARIA role searchbox.' n_selections=0
diff --git a/content/test/data/accessibility/aria/aria-searchbox-with-selection-expected-mac.txt b/content/test/data/accessibility/aria/aria-searchbox-with-selection-expected-mac.txt
index ad6b005..fe4bf976 100644
--- a/content/test/data/accessibility/aria/aria-searchbox-with-selection-expected-mac.txt
+++ b/content/test/data/accessibility/aria/aria-searchbox-with-selection-expected-mac.txt
@@ -1,3 +1,2 @@
 AXWebArea AXRoleDescription='HTML content'
 ++AXTextField AXSubrole=AXSearchField AXRoleDescription='search text field' AXValue='ARIA role searchbox.'
-++++AXStaticText AXRoleDescription='text' AXValue='ARIA role searchbox.'
diff --git a/content/test/data/accessibility/aria/aria-searchbox-with-selection-expected-win.txt b/content/test/data/accessibility/aria/aria-searchbox-with-selection-expected-win.txt
index 6d9618b..57ea7b64 100644
--- a/content/test/data/accessibility/aria/aria-searchbox-with-selection-expected-win.txt
+++ b/content/test/data/accessibility/aria/aria-searchbox-with-selection-expected-win.txt
@@ -1,3 +1,2 @@
 ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE ia2_hypertext='<obj0>' caret_offset=1 n_selections=1 selection_start=0 selection_end=1
 ++ROLE_SYSTEM_TEXT FOCUSABLE xml-roles:searchbox ia2_hypertext='ARIA role searchbox.' caret_offset=20 n_selections=1 selection_start=0 selection_end=20
-++++ROLE_SYSTEM_STATICTEXT name='ARIA role searchbox.' ia2_hypertext='ARIA role searchbox.' caret_offset=20 n_selections=1 selection_start=0 selection_end=20
diff --git a/content/test/data/accessibility/aria/aria-searchbox.html b/content/test/data/accessibility/aria/aria-searchbox.html
index 447fa07..2be4998 100644
--- a/content/test/data/accessibility/aria/aria-searchbox.html
+++ b/content/test/data/accessibility/aria/aria-searchbox.html
@@ -12,7 +12,8 @@
 <!DOCTYPE html>
 <html>
 <body>
-  <!-- There should be no caret because searchbox is not content editable. -->
+  <!-- There should be no selection on the document because the search box is
+      not content editable. -->
   <div id="searchbox" role="searchbox" tabindex="0">ARIA role searchbox.</div>
   <script>
     var searchbox = document.getElementById('searchbox');
diff --git a/content/test/data/accessibility/aria/aria-separator-expected-mac.txt b/content/test/data/accessibility/aria/aria-separator-expected-mac.txt
index 502c447..b4cff15 100644
--- a/content/test/data/accessibility/aria/aria-separator-expected-mac.txt
+++ b/content/test/data/accessibility/aria/aria-separator-expected-mac.txt
@@ -2,6 +2,5 @@
 ++AXGroup AXRoleDescription='group'
 ++++AXStaticText AXRoleDescription='text' AXValue='Before'
 ++AXSplitter AXRoleDescription='splitter'
-++++AXStaticText AXRoleDescription='text' AXValue='This is ARIA separator.'
 ++AXGroup AXRoleDescription='group'
 ++++AXStaticText AXRoleDescription='text' AXValue='After'
diff --git a/content/test/data/accessibility/aria/aria-separator-expected-win.txt b/content/test/data/accessibility/aria/aria-separator-expected-win.txt
index b4c7f55..70a8bc6 100644
--- a/content/test/data/accessibility/aria/aria-separator-expected-win.txt
+++ b/content/test/data/accessibility/aria/aria-separator-expected-win.txt
@@ -2,6 +2,5 @@
 ++IA2_ROLE_SECTION
 ++++ROLE_SYSTEM_STATICTEXT name='Before'
 ++ROLE_SYSTEM_SEPARATOR xml-roles:separator
-++++ROLE_SYSTEM_STATICTEXT name='This is ARIA separator.'
 ++IA2_ROLE_SECTION
 ++++ROLE_SYSTEM_STATICTEXT name='After'
diff --git a/content/test/data/accessibility/aria/aria-textbox.html b/content/test/data/accessibility/aria/aria-textbox.html
index d3f1e85f..25bb225 100644
--- a/content/test/data/accessibility/aria/aria-textbox.html
+++ b/content/test/data/accessibility/aria/aria-textbox.html
@@ -12,6 +12,8 @@
 <!DOCTYPE html>
 <html>
 <body>
+  <!-- There should be no selection on the document because the textboxes are
+      not content editable. -->
   <div role="textbox">TextBox1</div>
   <div role="textbox" aria-multiline="true">TextBox2</div>
 </body>
diff --git a/content/test/data/accessibility/html/math-expected-mac.txt b/content/test/data/accessibility/html/math-expected-mac.txt
index c99b0d23..b0f74f5 100644
--- a/content/test/data/accessibility/html/math-expected-mac.txt
+++ b/content/test/data/accessibility/html/math-expected-mac.txt
@@ -1,8 +1,3 @@
 AXWebArea AXRoleDescription='HTML content'
 ++AXGroup AXRoleDescription='group'
 ++++AXGroup AXSubrole=AXDocumentMath AXRoleDescription='math'
-++++++AXStaticText AXRoleDescription='text' AXValue='a'
-++++++AXStaticText AXRoleDescription='text' AXValue='2'
-++++++AXStaticText AXRoleDescription='text' AXValue='+'
-++++++AXStaticText AXRoleDescription='text' AXValue='b'
-++++++AXStaticText AXRoleDescription='text' AXValue='2'
diff --git a/content/test/data/accessibility/html/math-expected-win.txt b/content/test/data/accessibility/html/math-expected-win.txt
index fd6bdb0..99306aa4d 100644
--- a/content/test/data/accessibility/html/math-expected-win.txt
+++ b/content/test/data/accessibility/html/math-expected-win.txt
@@ -1,8 +1,3 @@
 ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE
 ++IA2_ROLE_SECTION
 ++++ROLE_SYSTEM_EQUATION
-++++++ROLE_SYSTEM_STATICTEXT name='a'
-++++++ROLE_SYSTEM_STATICTEXT name='2'
-++++++ROLE_SYSTEM_STATICTEXT name='+'
-++++++ROLE_SYSTEM_STATICTEXT name='b'
-++++++ROLE_SYSTEM_STATICTEXT name='2'
diff --git a/content/test/layouttest_support.cc b/content/test/layouttest_support.cc
index b33a505..68869aca 100644
--- a/content/test/layouttest_support.cc
+++ b/content/test/layouttest_support.cc
@@ -362,7 +362,7 @@
       render_process_host_impl->GetBluetoothDispatcherHost();
 
   if (dispatcher_host != NULL)
-    dispatcher_host->SetBluetoothAdapterForTesting(adapter.Pass());
+    dispatcher_host->SetBluetoothAdapterForTesting(std::move(adapter));
 }
 
 void SetGeofencingMockProvider(bool service_available) {
diff --git a/content/test/web_contents_observer_sanity_checker.cc b/content/test/web_contents_observer_sanity_checker.cc
index a27c96b..ce22bed 100644
--- a/content/test/web_contents_observer_sanity_checker.cc
+++ b/content/test/web_contents_observer_sanity_checker.cc
@@ -54,6 +54,12 @@
       static_cast<RenderFrameHostImpl*>(render_frame_host)->IsRenderFrameLive())
       << "RenderFrameCreated called on for a RenderFrameHost that thinks it is "
          "not alive.";
+
+  // Any child frame must be in the same BrowsingInstance as its parent.
+  if (render_frame_host->GetParent()) {
+    CHECK(render_frame_host->GetSiteInstance()->IsRelatedSiteInstance(
+        render_frame_host->GetParent()->GetSiteInstance()));
+  }
 }
 
 void WebContentsObserverSanityChecker::RenderFrameDeleted(
diff --git a/device/BUILD.gn b/device/BUILD.gn
index 5c53606..1d0e641 100644
--- a/device/BUILD.gn
+++ b/device/BUILD.gn
@@ -62,6 +62,7 @@
     "//device/bluetooth",
     "//device/bluetooth:mocks",
     "//device/nfc",
+    "//mojo/common",
     "//mojo/environment:chromium",
     "//mojo/public/cpp/bindings",
     "//net",
@@ -134,6 +135,7 @@
   # UsbContext is a libusb-specific object.
   if (!is_android && !is_ios) {
     sources += [ "usb/usb_context_unittest.cc" ]
+    deps += [ "//third_party/libusb" ]
   }
 
   if (is_android) {
diff --git a/device/bluetooth/BUILD.gn b/device/bluetooth/BUILD.gn
index aae32f6..4bfdaec 100644
--- a/device/bluetooth/BUILD.gn
+++ b/device/bluetooth/BUILD.gn
@@ -116,10 +116,11 @@
   deps = [
     "//base",
     "//crypto",
+    "//device/bluetooth/strings",
+    "//device/bluetooth/uribeacon",
+    "//ipc",
     "//net",
     "//ui/base",
-    "strings",
-    "uribeacon",
   ]
 
   if (is_android) {
diff --git a/device/devices_app/BUILD.gn b/device/devices_app/BUILD.gn
index 3b13142c..2601cf2 100644
--- a/device/devices_app/BUILD.gn
+++ b/device/devices_app/BUILD.gn
@@ -20,6 +20,7 @@
     "//device/core",
     "//device/devices_app/usb/public/interfaces",
     "//device/usb",
+    "//mojo/common",
     "//mojo/public/cpp/bindings",
     "//mojo/public/cpp/bindings:callback",
     "//net",
diff --git a/device/serial/BUILD.gn b/device/serial/BUILD.gn
index f66cedfe..474317e 100644
--- a/device/serial/BUILD.gn
+++ b/device/serial/BUILD.gn
@@ -49,6 +49,7 @@
   ]
   deps = [
     "//mojo/public/cpp/system",
+    "//net",
     "//third_party/re2",
   ]
 
@@ -56,7 +57,10 @@
     deps += [ "//device/udev_linux" ]
   }
   if (is_chromeos) {
-    deps += [ "//chromeos" ]
+    deps += [
+      "//chromeos",
+      "//dbus",
+    ]
   }
 }
 
diff --git a/device/serial/serial_io_handler.cc b/device/serial/serial_io_handler.cc
index 1cfb1cd..b9df970 100644
--- a/device/serial/serial_io_handler.cc
+++ b/device/serial/serial_io_handler.cc
@@ -12,7 +12,7 @@
 #if defined(OS_CHROMEOS)
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/permission_broker_client.h"
-#include "dbus/file_descriptor.h"
+#include "dbus/file_descriptor.h"  // nogncheck
 #endif  // defined(OS_CHROMEOS)
 
 namespace device {
diff --git a/device/test/test_device_client.cc b/device/test/test_device_client.cc
index f380c2c..ff6933e 100644
--- a/device/test/test_device_client.cc
+++ b/device/test/test_device_client.cc
@@ -4,8 +4,12 @@
 
 #include "device/test/test_device_client.h"
 
-#include "device/hid/hid_service.h"
-#include "device/usb/usb_service.h"
+// This file unconditionally includes these headers despite conditionally
+// depending on the corresponding targets. The code below needs the destructors
+// of the classes defined even when the classes are never instantiated.
+// TODO: This should probably be done more explicitly to avoid ambiguity.
+#include "device/hid/hid_service.h"  // nogncheck
+#include "device/usb/usb_service.h"  // nogncheck
 
 namespace device {
 
diff --git a/device/usb/usb_device_impl.cc b/device/usb/usb_device_impl.cc
index e1fc4025..ab9bd4ae 100644
--- a/device/usb/usb_device_impl.cc
+++ b/device/usb/usb_device_impl.cc
@@ -22,7 +22,7 @@
 #if defined(OS_CHROMEOS)
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/permission_broker_client.h"
-#include "dbus/file_descriptor.h"
+#include "dbus/file_descriptor.h"  // nogncheck
 #endif  // defined(OS_CHROMEOS)
 
 namespace device {
diff --git a/docs/clang.md b/docs/clang.md
index 5b5ec90..516d6fb 100644
--- a/docs/clang.md
+++ b/docs/clang.md
@@ -16,7 +16,7 @@
 
 Get clang (happens automatically during `gclient runhooks` on Mac and Linux):
 
-    tools/clang/scripts/update.sh
+    tools/clang/scripts/update.py
 
 (Only needs to be run once per checkout, and clang will be automatically updated
 by `gclient runhooks`.)
@@ -51,11 +51,17 @@
 
 If you're working on the plugin, you can build it locally like so:
 
-1.  Run `./tools/clang/scripts/update.sh --force-local-build --without-android`
+1.  Run `./tools/clang/scripts/update.py --force-local-build --without-android`
     to build the plugin.
-1.  Build with clang like described above.
+1.  Run `ninja -C third_party/llvm-build/Release+Asserts/` to build incrementally.
+1.  Build with clang like described above, but, if you use goma, disable it.
 
-TODO: writing_clang_plugins does not exist.
+To test the FindBadConstructs plugin, run:
+
+    (cd tools/clang/plugins/tests && \
+     ./test.sh ../../../../third_party/llvm-build/Release+Asserts/bin/clang \
+               ../../../../third_party/llvm-build/Release+Asserts/lib/libFindBadConstructs.so)
+
 To run [other plugins](writing_clang_plugins.md), add these to your
 `GYP_DEFINES`:
 
@@ -122,6 +128,6 @@
 
 If your clang revision is very different from the one currently used in chromium
 
-*   Check `tools/clang/scripts/update.sh` to find chromium's clang revision
+*   Check `tools/clang/scripts/update.py` to find chromium's clang revision
 *   You might have to tweak warning flags. Or you could set `werror=` in the
     line above to disable warnings as errors (but this only works on Linux).
diff --git a/extensions/browser/api/cast_channel/cast_framer.cc b/extensions/browser/api/cast_channel/cast_framer.cc
index b69a65f9..3d208396 100644
--- a/extensions/browser/api/cast_channel/cast_framer.cc
+++ b/extensions/browser/api/cast_channel/cast_framer.cc
@@ -6,6 +6,8 @@
 
 #include <stdlib.h>
 
+#include <limits>
+
 #include "base/numerics/safe_conversions.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/sys_byteorder.h"
@@ -26,7 +28,7 @@
 }
 
 void MessageFramer::MessageHeader::SetMessageSize(size_t size) {
-  DCHECK_LT(size, static_cast<size_t>(kuint32max));
+  DCHECK_LT(size, static_cast<size_t>(std::numeric_limits<uint32_t>::max()));
   DCHECK_GT(size, 0U);
   message_size = size;
 }
@@ -47,7 +49,7 @@
 // if bit-for-bit compatible.
 void MessageFramer::MessageHeader::Deserialize(char* data,
                                                MessageHeader* header) {
-  uint32 message_size;
+  uint32_t message_size;
   memcpy(&message_size, data, header_size());
   header->message_size =
       base::checked_cast<size_t>(base::NetToHost32(message_size));
@@ -55,7 +57,7 @@
 
 // static
 size_t MessageFramer::MessageHeader::header_size() {
-  return sizeof(uint32);
+  return sizeof(uint32_t);
 }
 
 // static
@@ -65,7 +67,7 @@
 
 std::string MessageFramer::MessageHeader::ToString() {
   return "{message_size: " +
-         base::UintToString(static_cast<uint32>(message_size)) + "}";
+         base::UintToString(static_cast<uint32_t>(message_size)) + "}";
 }
 
 // static
@@ -120,7 +122,7 @@
     return scoped_ptr<CastMessage>();
   }
 
-  DCHECK_EQ(base::checked_cast<int32>(message_bytes_received_),
+  DCHECK_EQ(base::checked_cast<int32_t>(message_bytes_received_),
             input_buffer_->offset());
   CHECK_LE(num_bytes, BytesRequested());
   message_bytes_received_ += num_bytes;
diff --git a/extensions/browser/api/cast_channel/cast_framer.h b/extensions/browser/api/cast_channel/cast_framer.h
index 81c9f90..6a913ab 100644
--- a/extensions/browser/api/cast_channel/cast_framer.h
+++ b/extensions/browser/api/cast_channel/cast_framer.h
@@ -5,9 +5,10 @@
 #ifndef EXTENSIONS_BROWSER_API_CAST_CHANNEL_CAST_FRAMER_H_
 #define EXTENSIONS_BROWSER_API_CAST_CHANNEL_CAST_FRAMER_H_
 
+#include <stdint.h>
+
 #include <string>
 
-#include "base/basictypes.h"
 #include "extensions/common/api/cast_channel.h"
 #include "net/base/io_buffer.h"
 
diff --git a/extensions/browser/api/guest_view/web_view/web_view_internal_api.cc b/extensions/browser/api/guest_view/web_view/web_view_internal_api.cc
index b6a8ab607..ce1acc1 100644
--- a/extensions/browser/api/guest_view/web_view/web_view_internal_api.cc
+++ b/extensions/browser/api/guest_view/web_view/web_view_internal_api.cc
@@ -287,9 +287,11 @@
   if (!args_->GetString(1, &src))
     return false;
 
+  // Set |guest_src_| here, but do not return false if it is invalid.
+  // Instead, let it continue with the normal page load sequence,
+  // which will result in the usual LOAD_ABORT event in the case where
+  // the URL is invalid.
   guest_src_ = GURL(src);
-  if (!guest_src_.is_valid())
-    return false;
 
   base::DictionaryValue* details_value = NULL;
   if (!args_->GetDictionary(2, &details_value))
diff --git a/extensions/common/constants.cc b/extensions/common/constants.cc
index ff10df9a..8d079b2 100644
--- a/extensions/common/constants.cc
+++ b/extensions/common/constants.cc
@@ -75,15 +75,6 @@
 
 const size_t kNumExtensionIconSizes = arraysize(kExtensionIconSizes);
 
-const IconRepresentationInfo kExtensionActionIconSizes[] = {
-  { EXTENSION_ICON_ACTION, "19", ui::SCALE_FACTOR_100P },
-  { 2 * EXTENSION_ICON_ACTION, "38", ui::SCALE_FACTOR_200P }
-};
-
-static_assert(kNumExtensionActionIconSizes ==
-              arraysize(kExtensionActionIconSizes),
-              "num action icon sizes must be in sync with action icon sizes");
-
 const char kPdfExtensionId[] = "mhjfbmdgcfjbbpaeojofohoefgiehjai";
 const char kQuickOfficeComponentExtensionId[] =
     "bpmcpldpdmajfigpchkicefoigmkfalc";
diff --git a/extensions/common/constants.h b/extensions/common/constants.h
index 7af8701..8022896 100644
--- a/extensions/common/constants.h
+++ b/extensions/common/constants.h
@@ -194,20 +194,6 @@
 extern const int kExtensionIconSizes[];
 extern const size_t kNumExtensionIconSizes;
 
-struct IconRepresentationInfo {
-  // Size in pixels.
-  const int size;
-  // Size as a string that will be used to retrieve representation value from
-  // ExtensionAction SetIcon function arguments.
-  const char* const size_string;
-  // Scale factor for which the representation should be used.
-  const ui::ScaleFactor scale;
-};
-
-// The icon representations for extension actions.
-extern const IconRepresentationInfo kExtensionActionIconSizes[];
-const size_t kNumExtensionActionIconSizes = 2u;
-
 // The extension id of the PDF extension.
 extern const char kPdfExtensionId[];
 
diff --git a/extensions/common/manifest_handler_helpers.cc b/extensions/common/manifest_handler_helpers.cc
index d3dfea6..7186321 100644
--- a/extensions/common/manifest_handler_helpers.cc
+++ b/extensions/common/manifest_handler_helpers.cc
@@ -59,6 +59,27 @@
   return true;
 }
 
+bool LoadAllIconsFromDictionary(const base::DictionaryValue* icons_value,
+                                ExtensionIconSet* icons,
+                                base::string16* error) {
+  DCHECK(icons);
+  for (base::DictionaryValue::Iterator iterator(*icons_value);
+       !iterator.IsAtEnd(); iterator.Advance()) {
+    int size = 0;
+    std::string icon_path;
+    if (!base::StringToInt(iterator.key(), &size) ||
+        !iterator.value().GetAsString(&icon_path) ||
+        !NormalizeAndValidatePath(&icon_path)) {
+      *error = ErrorUtils::FormatErrorMessageUTF16(errors::kInvalidIconPath,
+                                                   iterator.key());
+      return false;
+    }
+
+    icons->Add(size, icon_path);
+  }
+  return true;
+}
+
 }  // namespace manifest_handler_helpers
 
 }  // namespace extensions
diff --git a/extensions/common/manifest_handler_helpers.h b/extensions/common/manifest_handler_helpers.h
index 01fe6cc..4f88174 100644
--- a/extensions/common/manifest_handler_helpers.h
+++ b/extensions/common/manifest_handler_helpers.h
@@ -33,6 +33,11 @@
                              ExtensionIconSet* icons,
                              base::string16* error);
 
+// As above, but loads all icons in |icons_value|.
+bool LoadAllIconsFromDictionary(const base::DictionaryValue* icons_value,
+                                ExtensionIconSet* icons,
+                                base::string16* error);
+
 }  // namespace manifest_handler_helpers
 }  // namespace extensions
 
diff --git a/extensions/renderer/resources/media_router_bindings.js b/extensions/renderer/resources/media_router_bindings.js
index 6bc357d86..7bf09d3 100644
--- a/extensions/renderer/resources/media_router_bindings.js
+++ b/extensions/renderer/resources/media_router_bindings.js
@@ -29,6 +29,7 @@
   function sinkToMojo_(sink) {
     return new mediaRouterMojom.MediaSink({
       'name': sink.friendlyName,
+      'description': sink.description,
       'sink_id': sink.id,
       'icon_type': sinkIconTypeToMojo(sink.iconType),
     });
diff --git a/gin/modules/console.cc b/gin/modules/console.cc
index 231d8fc..63fc41e 100644
--- a/gin/modules/console.cc
+++ b/gin/modules/console.cc
@@ -4,7 +4,7 @@
 
 #include "gin/modules/console.h"
 
-#include <iostream>
+#include <stdio.h>
 
 #include "base/strings/string_util.h"
 #include "gin/arguments.h"
@@ -25,7 +25,7 @@
     args->ThrowError();
     return;
   }
-  std::cout << base::JoinString(messages, " ") << std::endl;
+  printf("%s\n", base::JoinString(messages, " ").c_str());
 }
 
 WrapperInfo g_wrapper_info = { kEmbedderNativeGin };
diff --git a/gpu/BUILD.gn b/gpu/BUILD.gn
index 7193022c..0462e45 100644
--- a/gpu/BUILD.gn
+++ b/gpu/BUILD.gn
@@ -127,6 +127,7 @@
     "command_buffer/tests/gl_copy_texture_CHROMIUM_unittest.cc",
     "command_buffer/tests/gl_cube_map_texture_unittest.cc",
     "command_buffer/tests/gl_depth_texture_unittest.cc",
+    "command_buffer/tests/gl_ext_blend_func_extended_unittest.cc",
     "command_buffer/tests/gl_ext_multisample_compatibility_unittest.cc",
     "command_buffer/tests/gl_ext_srgb_unittest.cc",
     "command_buffer/tests/gl_fence_sync_unittest.cc",
diff --git a/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_ycbcr_420v_image.txt b/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_ycbcr_420v_image.txt
new file mode 100644
index 0000000..c83453ec
--- /dev/null
+++ b/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_ycbcr_420v_image.txt
@@ -0,0 +1,48 @@
+Name
+
+    CHROMIUM_ycbcr_420v_image
+
+Name Strings
+
+    GL_CHROMIUM_ycbcr_420v_image
+
+Version
+
+    Last Modifed Date: October 26, 2015
+
+Dependencies
+
+    OpenGL ES 2.0 is required.
+
+    GL_CHROMIUM_image is required.
+
+Overview
+
+    This extension provides a new internal image format to use when creating an
+    image from underlying '420v' buffers.
+
+    This extension is useful in conjunction with CreateImageCHROMIUM and
+    CreateGpuMemoryBufferImageCHROMIUM to define the format of GpuMemoryBuffer
+    backing the image.
+
+New Procedures and Functions
+
+    None.
+
+Errors
+
+    None.
+
+New Tokens
+
+    Accepted by the <internalformat> parameter of CreateImageCHROMIUM, and
+    <internalformat> parameter of CreateGpuMemoryBufferImageCHROMIUM:
+        GL_RGB_YCBCR_420V_CHROMIUM 0x78FC
+
+New State
+
+    None.
+
+Revision History
+
+    10/26/2015   Documented the extension
diff --git a/gpu/GLES2/gl2chromium_autogen.h b/gpu/GLES2/gl2chromium_autogen.h
index 0cea2ef..f01a448 100644
--- a/gpu/GLES2/gl2chromium_autogen.h
+++ b/gpu/GLES2/gl2chromium_autogen.h
@@ -376,5 +376,9 @@
 #define glBlendBarrierKHR GLES2_GET_FUN(BlendBarrierKHR)
 #define glApplyScreenSpaceAntialiasingCHROMIUM \
   GLES2_GET_FUN(ApplyScreenSpaceAntialiasingCHROMIUM)
+#define glBindFragDataLocationIndexedEXT \
+  GLES2_GET_FUN(BindFragDataLocationIndexedEXT)
+#define glBindFragDataLocationEXT GLES2_GET_FUN(BindFragDataLocationEXT)
+#define glGetFragDataIndexEXT GLES2_GET_FUN(GetFragDataIndexEXT)
 
 #endif  // GPU_GLES2_GL2CHROMIUM_AUTOGEN_H_
diff --git a/gpu/GLES2/gl2extchromium.h b/gpu/GLES2/gl2extchromium.h
index f3c787f6..8118de0 100644
--- a/gpu/GLES2/gl2extchromium.h
+++ b/gpu/GLES2/gl2extchromium.h
@@ -123,6 +123,10 @@
 #define GL_RGB_YCBCR_422_CHROMIUM 0x78FB
 #endif
 
+#ifndef GL_RGB_YCBCR_420V_CHROMIUM
+#define GL_RGB_YCBCR_420V_CHROMIUM 0x78FC
+#endif
+
 #ifdef GL_GLEXT_PROTOTYPES
 GL_APICALL GLuint GL_APIENTRY glCreateGpuMemoryBufferImageCHROMIUM(
     GLsizei width,
@@ -1165,12 +1169,47 @@
 
 #endif /* GL_CHROMIUM_path_rendering */
 
+
 #ifndef GL_EXT_multisample_compatibility
 #define GL_EXT_multisample_compatibility 1
 #define GL_MULTISAMPLE_EXT 0x809D
 #define GL_SAMPLE_ALPHA_TO_ONE_EXT 0x809F
 #endif /* GL_EXT_multisample_compatiblity */
 
+#ifndef GL_EXT_blend_func_extended
+#define GL_EXT_blend_func_extended 1
+
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glBindFragDataLocationIndexedEXT(GLuint program,
+                                                             GLuint colorNumber,
+                                                             GLuint index,
+                                                             const char* name);
+GL_APICALL void GL_APIENTRY glBindFragDataLocationEXT(GLuint program,
+                                                      GLuint colorNumber,
+                                                      const char* name);
+GL_APICALL GLint GL_APIENTRY glGetFragDataIndexEXT(GLuint program,
+                                                   const char* name);
+#endif
+
+typedef void(GL_APIENTRYP PFNGLBINDFRAGDATALOCATIONINDEXEDEXT)(
+    GLuint program,
+    GLuint colorNumber,
+    GLuint index,
+    const char* name);
+typedef void(GL_APIENTRYP PFNGLBINDFRAGDATALOCATIONEXT)(GLuint program,
+                                                        GLuint colorNumber,
+                                                        const char* name);
+typedef GLint(GL_APIENTRYP PFNGLGETFRAGDATAINDEXEXT)(GLuint program,
+                                                     const GLchar* name);
+
+#define GL_SRC_ALPHA_SATURATE_EXT 0x0308
+#define GL_SRC1_ALPHA_EXT 0x8589  // OpenGL 1.5 token value
+#define GL_SRC1_COLOR_EXT 0x88F9
+#define GL_ONE_MINUS_SRC1_COLOR_EXT 0x88FA
+#define GL_ONE_MINUS_SRC1_ALPHA_EXT 0x88FB
+#define GL_MAX_DUAL_SOURCE_DRAW_BUFFERS_EXT 0x88FC
+#endif /* GL_EXT_blend_func_extended */
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/gpu/command_buffer/build_gles2_cmd_buffer.py b/gpu/command_buffer/build_gles2_cmd_buffer.py
index 6b672b2..76708f5 100755
--- a/gpu/command_buffer/build_gles2_cmd_buffer.py
+++ b/gpu/command_buffer/build_gles2_cmd_buffer.py
@@ -1949,6 +1949,7 @@
       'GL_RGB',
       'GL_RGB_YUV_420_CHROMIUM',
       'GL_RGB_YCBCR_422_CHROMIUM',
+      'GL_RGB_YCBCR_420V_CHROMIUM',
       'GL_RGBA',
     ],
   },
@@ -2863,6 +2864,16 @@
     'result': ['GLint'],
     'error_return': -1,
   },
+  'GetFragDataIndexEXT': {
+    'type': 'Custom',
+    'data_transfer_methods': ['shm'],
+    'cmd_args':
+        'GLidProgram program, uint32_t name_bucket_id, GLint* index',
+    'result': ['GLint'],
+    'error_return': -1,
+    'extension': 'EXT_blend_func_extended',
+    'extension_flag': 'ext_blend_func_extended',
+  },
   'GetFragDataLocation': {
     'type': 'Custom',
     'data_transfer_methods': ['shm'],
@@ -4016,6 +4027,22 @@
     'extension': True,
     'chromium': True,
   },
+  'BindFragDataLocationEXT': {
+    'type': 'GLchar',
+    'data_transfer_methods': ['bucket'],
+    'needs_size': True,
+    'gl_test_func': 'DoBindFragDataLocationEXT',
+    'extension': 'EXT_blend_func_extended',
+    'extension_flag': 'ext_blend_func_extended',
+  },
+  'BindFragDataLocationIndexedEXT': {
+    'type': 'GLchar',
+    'data_transfer_methods': ['bucket'],
+    'needs_size': True,
+    'gl_test_func': 'DoBindFragDataLocationIndexedEXT',
+    'extension': 'EXT_blend_func_extended',
+    'extension_flag': 'ext_blend_func_extended',
+  },
   'BindUniformLocationCHROMIUM': {
     'type': 'GLchar',
     'extension': 'CHROMIUM_bind_uniform_location',
diff --git a/gpu/command_buffer/client/gles2_c_lib_autogen.h b/gpu/command_buffer/client/gles2_c_lib_autogen.h
index b274a6b..8cb59a9 100644
--- a/gpu/command_buffer/client/gles2_c_lib_autogen.h
+++ b/gpu/command_buffer/client/gles2_c_lib_autogen.h
@@ -1704,6 +1704,21 @@
 void GL_APIENTRY GLES2ApplyScreenSpaceAntialiasingCHROMIUM() {
   gles2::GetGLContext()->ApplyScreenSpaceAntialiasingCHROMIUM();
 }
+void GL_APIENTRY GLES2BindFragDataLocationIndexedEXT(GLuint program,
+                                                     GLuint colorNumber,
+                                                     GLuint index,
+                                                     const char* name) {
+  gles2::GetGLContext()->BindFragDataLocationIndexedEXT(program, colorNumber,
+                                                        index, name);
+}
+void GL_APIENTRY GLES2BindFragDataLocationEXT(GLuint program,
+                                              GLuint colorNumber,
+                                              const char* name) {
+  gles2::GetGLContext()->BindFragDataLocationEXT(program, colorNumber, name);
+}
+GLint GL_APIENTRY GLES2GetFragDataIndexEXT(GLuint program, const char* name) {
+  return gles2::GetGLContext()->GetFragDataIndexEXT(program, name);
+}
 
 namespace gles2 {
 
@@ -2994,6 +3009,19 @@
             glApplyScreenSpaceAntialiasingCHROMIUM),
     },
     {
+        "glBindFragDataLocationIndexedEXT",
+        reinterpret_cast<GLES2FunctionPointer>(
+            glBindFragDataLocationIndexedEXT),
+    },
+    {
+        "glBindFragDataLocationEXT",
+        reinterpret_cast<GLES2FunctionPointer>(glBindFragDataLocationEXT),
+    },
+    {
+        "glGetFragDataIndexEXT",
+        reinterpret_cast<GLES2FunctionPointer>(glGetFragDataIndexEXT),
+    },
+    {
         NULL, NULL,
     },
 };
diff --git a/gpu/command_buffer/client/gles2_cmd_helper_autogen.h b/gpu/command_buffer/client/gles2_cmd_helper_autogen.h
index b5cf24cd..b87750a 100644
--- a/gpu/command_buffer/client/gles2_cmd_helper_autogen.h
+++ b/gpu/command_buffer/client/gles2_cmd_helper_autogen.h
@@ -3166,4 +3166,36 @@
   }
 }
 
+void BindFragDataLocationIndexedEXTBucket(GLuint program,
+                                          GLuint colorNumber,
+                                          GLuint index,
+                                          uint32_t name_bucket_id) {
+  gles2::cmds::BindFragDataLocationIndexedEXTBucket* c =
+      GetCmdSpace<gles2::cmds::BindFragDataLocationIndexedEXTBucket>();
+  if (c) {
+    c->Init(program, colorNumber, index, name_bucket_id);
+  }
+}
+
+void BindFragDataLocationEXTBucket(GLuint program,
+                                   GLuint colorNumber,
+                                   uint32_t name_bucket_id) {
+  gles2::cmds::BindFragDataLocationEXTBucket* c =
+      GetCmdSpace<gles2::cmds::BindFragDataLocationEXTBucket>();
+  if (c) {
+    c->Init(program, colorNumber, name_bucket_id);
+  }
+}
+
+void GetFragDataIndexEXT(GLuint program,
+                         uint32_t name_bucket_id,
+                         uint32_t index_shm_id,
+                         uint32_t index_shm_offset) {
+  gles2::cmds::GetFragDataIndexEXT* c =
+      GetCmdSpace<gles2::cmds::GetFragDataIndexEXT>();
+  if (c) {
+    c->Init(program, name_bucket_id, index_shm_id, index_shm_offset);
+  }
+}
+
 #endif  // GPU_COMMAND_BUFFER_CLIENT_GLES2_CMD_HELPER_AUTOGEN_H_
diff --git a/gpu/command_buffer/client/gles2_implementation.cc b/gpu/command_buffer/client/gles2_implementation.cc
index 9b52768..7c7f99d6 100644
--- a/gpu/command_buffer/client/gles2_implementation.cc
+++ b/gpu/command_buffer/client/gles2_implementation.cc
@@ -1396,6 +1396,33 @@
   CheckGLError();
 }
 
+void GLES2Implementation::BindFragDataLocationEXT(GLuint program,
+                                                  GLuint colorName,
+                                                  const char* name) {
+  GPU_CLIENT_SINGLE_THREAD_CHECK();
+  GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBindFragDataLocationEXT("
+                     << program << ", " << colorName << ", " << name << ")");
+  SetBucketAsString(kResultBucketId, name);
+  helper_->BindFragDataLocationEXTBucket(program, colorName, kResultBucketId);
+  helper_->SetBucketSize(kResultBucketId, 0);
+  CheckGLError();
+}
+
+void GLES2Implementation::BindFragDataLocationIndexedEXT(GLuint program,
+                                                         GLuint colorName,
+                                                         GLuint index,
+                                                         const char* name) {
+  GPU_CLIENT_SINGLE_THREAD_CHECK();
+  GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBindFragDataLocationEXT("
+                     << program << ", " << colorName << ", " << index << ", "
+                     << name << ")");
+  SetBucketAsString(kResultBucketId, name);
+  helper_->BindFragDataLocationIndexedEXTBucket(program, colorName, index,
+                                                kResultBucketId);
+  helper_->SetBucketSize(kResultBucketId, 0);
+  CheckGLError();
+}
+
 void GLES2Implementation::BindUniformLocationCHROMIUM(
   GLuint program, GLint location, const char* name) {
   GPU_CLIENT_SINGLE_THREAD_CHECK();
@@ -1607,6 +1634,35 @@
   return got_value;
 }
 
+GLint GLES2Implementation::GetFragDataIndexEXTHelper(GLuint program,
+                                                     const char* name) {
+  typedef cmds::GetFragDataIndexEXT::Result Result;
+  Result* result = GetResultAs<Result*>();
+  if (!result) {
+    return -1;
+  }
+  *result = -1;
+  SetBucketAsCString(kResultBucketId, name);
+  helper_->GetFragDataIndexEXT(program, kResultBucketId, GetResultShmId(),
+                               GetResultShmOffset());
+  WaitForCmd();
+  helper_->SetBucketSize(kResultBucketId, 0);
+  return *result;
+}
+
+GLint GLES2Implementation::GetFragDataIndexEXT(GLuint program,
+                                               const char* name) {
+  GPU_CLIENT_SINGLE_THREAD_CHECK();
+  GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetFragDataIndexEXT(" << program
+                     << ", " << name << ")");
+  TRACE_EVENT0("gpu", "GLES2::GetFragDataIndexEXT");
+  GLint loc = share_group_->program_info_manager()->GetFragDataIndex(
+      this, program, name);
+  GPU_CLIENT_LOG("returned " << loc);
+  CheckGLError();
+  return loc;
+}
+
 GLint GLES2Implementation::GetFragDataLocationHelper(
     GLuint program, const char* name) {
   typedef cmds::GetFragDataLocation::Result Result;
@@ -5572,6 +5628,7 @@
     case GL_RGB:
     case GL_RGBA:
     case GL_RGB_YCBCR_422_CHROMIUM:
+    case GL_RGB_YCBCR_420V_CHROMIUM:
     case GL_BGRA_EXT:
       return true;
     default:
diff --git a/gpu/command_buffer/client/gles2_implementation.h b/gpu/command_buffer/client/gles2_implementation.h
index 1c2eba9..1c55b83 100644
--- a/gpu/command_buffer/client/gles2_implementation.h
+++ b/gpu/command_buffer/client/gles2_implementation.h
@@ -215,6 +215,7 @@
   void GetProgramInfoCHROMIUMHelper(GLuint program, std::vector<int8>* result);
   GLint GetAttribLocationHelper(GLuint program, const char* name);
   GLint GetUniformLocationHelper(GLuint program, const char* name);
+  GLint GetFragDataIndexEXTHelper(GLuint program, const char* name);
   GLint GetFragDataLocationHelper(GLuint program, const char* name);
   bool GetActiveAttribHelper(
       GLuint program, GLuint index, GLsizei bufsize, GLsizei* length,
diff --git a/gpu/command_buffer/client/gles2_implementation_autogen.h b/gpu/command_buffer/client/gles2_implementation_autogen.h
index 0a4f886..10ebcc3 100644
--- a/gpu/command_buffer/client/gles2_implementation_autogen.h
+++ b/gpu/command_buffer/client/gles2_implementation_autogen.h
@@ -1184,4 +1184,15 @@
 
 void ApplyScreenSpaceAntialiasingCHROMIUM() override;
 
+void BindFragDataLocationIndexedEXT(GLuint program,
+                                    GLuint colorNumber,
+                                    GLuint index,
+                                    const char* name) override;
+
+void BindFragDataLocationEXT(GLuint program,
+                             GLuint colorNumber,
+                             const char* name) override;
+
+GLint GetFragDataIndexEXT(GLuint program, const char* name) override;
+
 #endif  // GPU_COMMAND_BUFFER_CLIENT_GLES2_IMPLEMENTATION_AUTOGEN_H_
diff --git a/gpu/command_buffer/client/gles2_interface_autogen.h b/gpu/command_buffer/client/gles2_interface_autogen.h
index 77872e7a..374cb26 100644
--- a/gpu/command_buffer/client/gles2_interface_autogen.h
+++ b/gpu/command_buffer/client/gles2_interface_autogen.h
@@ -885,4 +885,12 @@
 virtual GLenum GetGraphicsResetStatusKHR() = 0;
 virtual void BlendBarrierKHR() = 0;
 virtual void ApplyScreenSpaceAntialiasingCHROMIUM() = 0;
+virtual void BindFragDataLocationIndexedEXT(GLuint program,
+                                            GLuint colorNumber,
+                                            GLuint index,
+                                            const char* name) = 0;
+virtual void BindFragDataLocationEXT(GLuint program,
+                                     GLuint colorNumber,
+                                     const char* name) = 0;
+virtual GLint GetFragDataIndexEXT(GLuint program, const char* name) = 0;
 #endif  // GPU_COMMAND_BUFFER_CLIENT_GLES2_INTERFACE_AUTOGEN_H_
diff --git a/gpu/command_buffer/client/gles2_interface_stub_autogen.h b/gpu/command_buffer/client/gles2_interface_stub_autogen.h
index 5469525..489afa2 100644
--- a/gpu/command_buffer/client/gles2_interface_stub_autogen.h
+++ b/gpu/command_buffer/client/gles2_interface_stub_autogen.h
@@ -859,4 +859,12 @@
 GLenum GetGraphicsResetStatusKHR() override;
 void BlendBarrierKHR() override;
 void ApplyScreenSpaceAntialiasingCHROMIUM() override;
+void BindFragDataLocationIndexedEXT(GLuint program,
+                                    GLuint colorNumber,
+                                    GLuint index,
+                                    const char* name) override;
+void BindFragDataLocationEXT(GLuint program,
+                             GLuint colorNumber,
+                             const char* name) override;
+GLint GetFragDataIndexEXT(GLuint program, const char* name) override;
 #endif  // GPU_COMMAND_BUFFER_CLIENT_GLES2_INTERFACE_STUB_AUTOGEN_H_
diff --git a/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h b/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h
index 867652f..148f3af 100644
--- a/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h
+++ b/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h
@@ -1159,4 +1159,16 @@
 }
 void GLES2InterfaceStub::BlendBarrierKHR() {}
 void GLES2InterfaceStub::ApplyScreenSpaceAntialiasingCHROMIUM() {}
+void GLES2InterfaceStub::BindFragDataLocationIndexedEXT(
+    GLuint /* program */,
+    GLuint /* colorNumber */,
+    GLuint /* index */,
+    const char* /* name */) {}
+void GLES2InterfaceStub::BindFragDataLocationEXT(GLuint /* program */,
+                                                 GLuint /* colorNumber */,
+                                                 const char* /* name */) {}
+GLint GLES2InterfaceStub::GetFragDataIndexEXT(GLuint /* program */,
+                                              const char* /* name */) {
+  return 0;
+}
 #endif  // GPU_COMMAND_BUFFER_CLIENT_GLES2_INTERFACE_STUB_IMPL_AUTOGEN_H_
diff --git a/gpu/command_buffer/client/gles2_trace_implementation_autogen.h b/gpu/command_buffer/client/gles2_trace_implementation_autogen.h
index 209215e..8347572 100644
--- a/gpu/command_buffer/client/gles2_trace_implementation_autogen.h
+++ b/gpu/command_buffer/client/gles2_trace_implementation_autogen.h
@@ -859,4 +859,12 @@
 GLenum GetGraphicsResetStatusKHR() override;
 void BlendBarrierKHR() override;
 void ApplyScreenSpaceAntialiasingCHROMIUM() override;
+void BindFragDataLocationIndexedEXT(GLuint program,
+                                    GLuint colorNumber,
+                                    GLuint index,
+                                    const char* name) override;
+void BindFragDataLocationEXT(GLuint program,
+                             GLuint colorNumber,
+                             const char* name) override;
+GLint GetFragDataIndexEXT(GLuint program, const char* name) override;
 #endif  // GPU_COMMAND_BUFFER_CLIENT_GLES2_TRACE_IMPLEMENTATION_AUTOGEN_H_
diff --git a/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h b/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h
index 77c6ab6..5f67456d 100644
--- a/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h
+++ b/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h
@@ -2475,4 +2475,27 @@
   gl_->ApplyScreenSpaceAntialiasingCHROMIUM();
 }
 
+void GLES2TraceImplementation::BindFragDataLocationIndexedEXT(
+    GLuint program,
+    GLuint colorNumber,
+    GLuint index,
+    const char* name) {
+  TRACE_EVENT_BINARY_EFFICIENT0("gpu",
+                                "GLES2Trace::BindFragDataLocationIndexedEXT");
+  gl_->BindFragDataLocationIndexedEXT(program, colorNumber, index, name);
+}
+
+void GLES2TraceImplementation::BindFragDataLocationEXT(GLuint program,
+                                                       GLuint colorNumber,
+                                                       const char* name) {
+  TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::BindFragDataLocationEXT");
+  gl_->BindFragDataLocationEXT(program, colorNumber, name);
+}
+
+GLint GLES2TraceImplementation::GetFragDataIndexEXT(GLuint program,
+                                                    const char* name) {
+  TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::GetFragDataIndexEXT");
+  return gl_->GetFragDataIndexEXT(program, name);
+}
+
 #endif  // GPU_COMMAND_BUFFER_CLIENT_GLES2_TRACE_IMPLEMENTATION_IMPL_AUTOGEN_H_
diff --git a/gpu/command_buffer/client/mapped_memory.cc b/gpu/command_buffer/client/mapped_memory.cc
index fcc9113..dcfead22 100644
--- a/gpu/command_buffer/client/mapped_memory.cc
+++ b/gpu/command_buffer/client/mapped_memory.cc
@@ -56,9 +56,7 @@
       this);
 
   CommandBuffer* cmd_buf = helper_->command_buffer();
-  for (MemoryChunkVector::iterator iter = chunks_.begin();
-       iter != chunks_.end(); ++iter) {
-    MemoryChunk* chunk = *iter;
+  for (auto& chunk : chunks_) {
     cmd_buf->DestroyTransferBuffer(chunk->shm_id());
   }
 }
@@ -70,8 +68,7 @@
   if (size <= allocated_memory_) {
     size_t total_bytes_in_use = 0;
     // See if any of the chunks can satisfy this request.
-    for (size_t ii = 0; ii < chunks_.size(); ++ii) {
-      MemoryChunk* chunk = chunks_[ii];
+    for (auto& chunk : chunks_) {
       chunk->FreeUnused();
       total_bytes_in_use += chunk->bytes_in_use();
       if (chunk->GetLargestFreeSizeWithoutWaiting() >= size) {
@@ -89,8 +86,7 @@
     if (max_free_bytes_ != kNoLimit &&
         (allocated_memory_ - total_bytes_in_use) >= max_free_bytes_) {
       TRACE_EVENT0("gpu", "MappedMemoryManager::Alloc::wait");
-      for (size_t ii = 0; ii < chunks_.size(); ++ii) {
-        MemoryChunk* chunk = chunks_[ii];
+      for (auto& chunk : chunks_) {
         if (chunk->GetLargestFreeSizeWithWaiting() >= size) {
           void* mem = chunk->Alloc(size);
           DCHECK(mem);
@@ -120,7 +116,7 @@
   DCHECK(shm.get());
   MemoryChunk* mc = new MemoryChunk(id, shm, helper_);
   allocated_memory_ += mc->GetSize();
-  chunks_.push_back(mc);
+  chunks_.push_back(make_scoped_ptr(mc));
   void* mem = mc->Alloc(size);
   DCHECK(mem);
   *shm_id = mc->shm_id();
@@ -129,8 +125,7 @@
 }
 
 void MappedMemoryManager::Free(void* pointer) {
-  for (size_t ii = 0; ii < chunks_.size(); ++ii) {
-    MemoryChunk* chunk = chunks_[ii];
+  for (auto& chunk : chunks_) {
     if (chunk->IsInChunk(pointer)) {
       chunk->Free(pointer);
       return;
@@ -140,8 +135,7 @@
 }
 
 void MappedMemoryManager::FreePendingToken(void* pointer, int32 token) {
-  for (size_t ii = 0; ii < chunks_.size(); ++ii) {
-    MemoryChunk* chunk = chunks_[ii];
+  for (auto& chunk : chunks_) {
     if (chunk->IsInChunk(pointer)) {
       chunk->FreePendingToken(pointer, token);
       return;
@@ -154,7 +148,7 @@
   CommandBuffer* cmd_buf = helper_->command_buffer();
   MemoryChunkVector::iterator iter = chunks_.begin();
   while (iter != chunks_.end()) {
-    MemoryChunk* chunk = *iter;
+    MemoryChunk* chunk = (*iter).get();
     chunk->FreeUnused();
     if (!chunk->InUse()) {
       cmd_buf->DestroyTransferBuffer(chunk->shm_id());
diff --git a/gpu/command_buffer/client/mapped_memory.h b/gpu/command_buffer/client/mapped_memory.h
index aad8647..8d312d8f 100644
--- a/gpu/command_buffer/client/mapped_memory.h
+++ b/gpu/command_buffer/client/mapped_memory.h
@@ -189,8 +189,7 @@
   size_t bytes_in_use() const {
     size_t bytes_in_use = 0;
     for (size_t ii = 0; ii < chunks_.size(); ++ii) {
-      MemoryChunk* chunk = chunks_[ii];
-      bytes_in_use += chunk->bytes_in_use();
+      bytes_in_use += chunks_[ii]->bytes_in_use();
     }
     return bytes_in_use;
   }
@@ -201,7 +200,7 @@
   }
 
  private:
-  typedef ScopedVector<MemoryChunk> MemoryChunkVector;
+  typedef std::vector<scoped_ptr<MemoryChunk>> MemoryChunkVector;
 
   // size a chunk is rounded up to.
   unsigned int chunk_size_multiple_;
diff --git a/gpu/command_buffer/client/program_info_manager.cc b/gpu/command_buffer/client/program_info_manager.cc
index 939473a..d047b57 100644
--- a/gpu/command_buffer/client/program_info_manager.cc
+++ b/gpu/command_buffer/client/program_info_manager.cc
@@ -160,6 +160,19 @@
   return GL_INVALID_INDEX;
 }
 
+GLint ProgramInfoManager::Program::GetFragDataIndex(
+    const std::string& name) const {
+  auto iter = frag_data_indices_.find(name);
+  if (iter == frag_data_indices_.end())
+    return -1;
+  return iter->second;
+}
+
+void ProgramInfoManager::Program::CacheFragDataIndex(const std::string& name,
+                                                     GLint index) {
+  frag_data_indices_[name] = index;
+}
+
 GLint ProgramInfoManager::Program::GetFragDataLocation(
     const std::string& name) const {
   base::hash_map<std::string, GLint>::const_iterator iter =
@@ -725,6 +738,31 @@
   return gl->GetUniformLocationHelper(program, name);
 }
 
+GLint ProgramInfoManager::GetFragDataIndex(GLES2Implementation* gl,
+                                           GLuint program,
+                                           const char* name) {
+  // TODO(zmo): make FragData indexes part of the ProgramInfo that are
+  // fetched from the service side.  See crbug.com/452104.
+  {
+    base::AutoLock auto_lock(lock_);
+    Program* info = GetProgramInfo(gl, program, kNone);
+    if (info) {
+      GLint possible_index = info->GetFragDataIndex(name);
+      if (possible_index != -1)
+        return possible_index;
+    }
+  }
+  GLint index = gl->GetFragDataIndexEXTHelper(program, name);
+  if (index != -1) {
+    base::AutoLock auto_lock(lock_);
+    Program* info = GetProgramInfo(gl, program, kNone);
+    if (info) {
+      info->CacheFragDataIndex(name, index);
+    }
+  }
+  return index;
+}
+
 GLint ProgramInfoManager::GetFragDataLocation(
     GLES2Implementation* gl, GLuint program, const char* name) {
   // TODO(zmo): make FragData locations part of the ProgramInfo that are
diff --git a/gpu/command_buffer/client/program_info_manager.h b/gpu/command_buffer/client/program_info_manager.h
index fa74ea58..fbae19ae 100644
--- a/gpu/command_buffer/client/program_info_manager.h
+++ b/gpu/command_buffer/client/program_info_manager.h
@@ -38,6 +38,10 @@
   GLint GetUniformLocation(
       GLES2Implementation* gl, GLuint program, const char* name);
 
+  GLint GetFragDataIndex(GLES2Implementation* gl,
+                         GLuint program,
+                         const char* name);
+
   GLint GetFragDataLocation(
       GLES2Implementation* gl, GLuint program, const char* name);
 
@@ -166,6 +170,9 @@
     bool GetUniformsiv(
         GLsizei count, const GLuint* indices, GLenum pname, GLint* params);
 
+    GLint GetFragDataIndex(const std::string& name) const;
+    void CacheFragDataIndex(const std::string& name, GLint index);
+
     GLint GetFragDataLocation(const std::string& name) const;
     void CacheFragDataLocation(const std::string& name, GLint loc);
 
@@ -232,6 +239,7 @@
     std::vector<UniformES3> uniforms_es3_;
 
     base::hash_map<std::string, GLint> frag_data_locations_;
+    base::hash_map<std::string, GLint> frag_data_indices_;
   };
 
   Program* GetProgramInfo(
diff --git a/gpu/command_buffer/cmd_buffer_functions.txt b/gpu/command_buffer/cmd_buffer_functions.txt
index 42ed5f5e..8c9baf034 100644
--- a/gpu/command_buffer/cmd_buffer_functions.txt
+++ b/gpu/command_buffer/cmd_buffer_functions.txt
@@ -352,3 +352,9 @@
 
 // Extension GL_CHROMIUM_screen_space_antialiasing
 GL_APICALL void GL_APIENTRY glApplyScreenSpaceAntialiasingCHROMIUM (void);
+
+// Extension EXT_blend_func_extended
+GL_APICALL void         GL_APIENTRY glBindFragDataLocationIndexedEXT (GLidProgram program, GLuint colorNumber, GLuint index, const char* name);
+GL_APICALL void         GL_APIENTRY glBindFragDataLocationEXT (GLidProgram program, GLuint colorNumber, const char* name);
+GL_APICALL GLint        GL_APIENTRY glGetFragDataIndexEXT (GLidProgram program, const char* name);
+
diff --git a/gpu/command_buffer/common/gles2_cmd_format_autogen.h b/gpu/command_buffer/common/gles2_cmd_format_autogen.h
index b26cea0..ec3a09b 100644
--- a/gpu/command_buffer/common/gles2_cmd_format_autogen.h
+++ b/gpu/command_buffer/common/gles2_cmd_format_autogen.h
@@ -15434,4 +15434,164 @@
     offsetof(ApplyScreenSpaceAntialiasingCHROMIUM, header) == 0,
     "offset of ApplyScreenSpaceAntialiasingCHROMIUM header should be 0");
 
+struct BindFragDataLocationIndexedEXTBucket {
+  typedef BindFragDataLocationIndexedEXTBucket ValueType;
+  static const CommandId kCmdId = kBindFragDataLocationIndexedEXTBucket;
+  static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+  static const uint8 cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3);
+
+  static uint32_t ComputeSize() {
+    return static_cast<uint32_t>(sizeof(ValueType));  // NOLINT
+  }
+
+  void SetHeader() { header.SetCmd<ValueType>(); }
+
+  void Init(GLuint _program,
+            GLuint _colorNumber,
+            GLuint _index,
+            uint32_t _name_bucket_id) {
+    SetHeader();
+    program = _program;
+    colorNumber = _colorNumber;
+    index = _index;
+    name_bucket_id = _name_bucket_id;
+  }
+
+  void* Set(void* cmd,
+            GLuint _program,
+            GLuint _colorNumber,
+            GLuint _index,
+            uint32_t _name_bucket_id) {
+    static_cast<ValueType*>(cmd)
+        ->Init(_program, _colorNumber, _index, _name_bucket_id);
+    return NextCmdAddress<ValueType>(cmd);
+  }
+
+  gpu::CommandHeader header;
+  uint32_t program;
+  uint32_t colorNumber;
+  uint32_t index;
+  uint32_t name_bucket_id;
+};
+
+static_assert(sizeof(BindFragDataLocationIndexedEXTBucket) == 20,
+              "size of BindFragDataLocationIndexedEXTBucket should be 20");
+static_assert(
+    offsetof(BindFragDataLocationIndexedEXTBucket, header) == 0,
+    "offset of BindFragDataLocationIndexedEXTBucket header should be 0");
+static_assert(
+    offsetof(BindFragDataLocationIndexedEXTBucket, program) == 4,
+    "offset of BindFragDataLocationIndexedEXTBucket program should be 4");
+static_assert(
+    offsetof(BindFragDataLocationIndexedEXTBucket, colorNumber) == 8,
+    "offset of BindFragDataLocationIndexedEXTBucket colorNumber should be 8");
+static_assert(
+    offsetof(BindFragDataLocationIndexedEXTBucket, index) == 12,
+    "offset of BindFragDataLocationIndexedEXTBucket index should be 12");
+static_assert(offsetof(BindFragDataLocationIndexedEXTBucket, name_bucket_id) ==
+                  16,
+              "offset of BindFragDataLocationIndexedEXTBucket name_bucket_id "
+              "should be 16");
+
+struct BindFragDataLocationEXTBucket {
+  typedef BindFragDataLocationEXTBucket ValueType;
+  static const CommandId kCmdId = kBindFragDataLocationEXTBucket;
+  static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+  static const uint8 cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3);
+
+  static uint32_t ComputeSize() {
+    return static_cast<uint32_t>(sizeof(ValueType));  // NOLINT
+  }
+
+  void SetHeader() { header.SetCmd<ValueType>(); }
+
+  void Init(GLuint _program, GLuint _colorNumber, uint32_t _name_bucket_id) {
+    SetHeader();
+    program = _program;
+    colorNumber = _colorNumber;
+    name_bucket_id = _name_bucket_id;
+  }
+
+  void* Set(void* cmd,
+            GLuint _program,
+            GLuint _colorNumber,
+            uint32_t _name_bucket_id) {
+    static_cast<ValueType*>(cmd)->Init(_program, _colorNumber, _name_bucket_id);
+    return NextCmdAddress<ValueType>(cmd);
+  }
+
+  gpu::CommandHeader header;
+  uint32_t program;
+  uint32_t colorNumber;
+  uint32_t name_bucket_id;
+};
+
+static_assert(sizeof(BindFragDataLocationEXTBucket) == 16,
+              "size of BindFragDataLocationEXTBucket should be 16");
+static_assert(offsetof(BindFragDataLocationEXTBucket, header) == 0,
+              "offset of BindFragDataLocationEXTBucket header should be 0");
+static_assert(offsetof(BindFragDataLocationEXTBucket, program) == 4,
+              "offset of BindFragDataLocationEXTBucket program should be 4");
+static_assert(
+    offsetof(BindFragDataLocationEXTBucket, colorNumber) == 8,
+    "offset of BindFragDataLocationEXTBucket colorNumber should be 8");
+static_assert(
+    offsetof(BindFragDataLocationEXTBucket, name_bucket_id) == 12,
+    "offset of BindFragDataLocationEXTBucket name_bucket_id should be 12");
+
+struct GetFragDataIndexEXT {
+  typedef GetFragDataIndexEXT ValueType;
+  static const CommandId kCmdId = kGetFragDataIndexEXT;
+  static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+  static const uint8 cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3);
+
+  typedef GLint Result;
+
+  static uint32_t ComputeSize() {
+    return static_cast<uint32_t>(sizeof(ValueType));  // NOLINT
+  }
+
+  void SetHeader() { header.SetCmd<ValueType>(); }
+
+  void Init(GLuint _program,
+            uint32_t _name_bucket_id,
+            uint32_t _index_shm_id,
+            uint32_t _index_shm_offset) {
+    SetHeader();
+    program = _program;
+    name_bucket_id = _name_bucket_id;
+    index_shm_id = _index_shm_id;
+    index_shm_offset = _index_shm_offset;
+  }
+
+  void* Set(void* cmd,
+            GLuint _program,
+            uint32_t _name_bucket_id,
+            uint32_t _index_shm_id,
+            uint32_t _index_shm_offset) {
+    static_cast<ValueType*>(cmd)
+        ->Init(_program, _name_bucket_id, _index_shm_id, _index_shm_offset);
+    return NextCmdAddress<ValueType>(cmd);
+  }
+
+  gpu::CommandHeader header;
+  uint32_t program;
+  uint32_t name_bucket_id;
+  uint32_t index_shm_id;
+  uint32_t index_shm_offset;
+};
+
+static_assert(sizeof(GetFragDataIndexEXT) == 20,
+              "size of GetFragDataIndexEXT should be 20");
+static_assert(offsetof(GetFragDataIndexEXT, header) == 0,
+              "offset of GetFragDataIndexEXT header should be 0");
+static_assert(offsetof(GetFragDataIndexEXT, program) == 4,
+              "offset of GetFragDataIndexEXT program should be 4");
+static_assert(offsetof(GetFragDataIndexEXT, name_bucket_id) == 8,
+              "offset of GetFragDataIndexEXT name_bucket_id should be 8");
+static_assert(offsetof(GetFragDataIndexEXT, index_shm_id) == 12,
+              "offset of GetFragDataIndexEXT index_shm_id should be 12");
+static_assert(offsetof(GetFragDataIndexEXT, index_shm_offset) == 16,
+              "offset of GetFragDataIndexEXT index_shm_offset should be 16");
+
 #endif  // GPU_COMMAND_BUFFER_COMMON_GLES2_CMD_FORMAT_AUTOGEN_H_
diff --git a/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h b/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h
index 95a8ab8..939ea4e 100644
--- a/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h
+++ b/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h
@@ -5298,4 +5298,50 @@
   CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
 }
 
+TEST_F(GLES2FormatTest, BindFragDataLocationIndexedEXTBucket) {
+  cmds::BindFragDataLocationIndexedEXTBucket& cmd =
+      *GetBufferAs<cmds::BindFragDataLocationIndexedEXTBucket>();
+  void* next_cmd =
+      cmd.Set(&cmd, static_cast<GLuint>(11), static_cast<GLuint>(12),
+              static_cast<GLuint>(13), static_cast<uint32_t>(14));
+  EXPECT_EQ(
+      static_cast<uint32_t>(cmds::BindFragDataLocationIndexedEXTBucket::kCmdId),
+      cmd.header.command);
+  EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+  EXPECT_EQ(static_cast<GLuint>(11), cmd.program);
+  EXPECT_EQ(static_cast<GLuint>(12), cmd.colorNumber);
+  EXPECT_EQ(static_cast<GLuint>(13), cmd.index);
+  EXPECT_EQ(static_cast<uint32_t>(14), cmd.name_bucket_id);
+  CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, BindFragDataLocationEXTBucket) {
+  cmds::BindFragDataLocationEXTBucket& cmd =
+      *GetBufferAs<cmds::BindFragDataLocationEXTBucket>();
+  void* next_cmd = cmd.Set(&cmd, static_cast<GLuint>(11),
+                           static_cast<GLuint>(12), static_cast<uint32_t>(13));
+  EXPECT_EQ(static_cast<uint32_t>(cmds::BindFragDataLocationEXTBucket::kCmdId),
+            cmd.header.command);
+  EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+  EXPECT_EQ(static_cast<GLuint>(11), cmd.program);
+  EXPECT_EQ(static_cast<GLuint>(12), cmd.colorNumber);
+  EXPECT_EQ(static_cast<uint32_t>(13), cmd.name_bucket_id);
+  CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, GetFragDataIndexEXT) {
+  cmds::GetFragDataIndexEXT& cmd = *GetBufferAs<cmds::GetFragDataIndexEXT>();
+  void* next_cmd =
+      cmd.Set(&cmd, static_cast<GLuint>(11), static_cast<uint32_t>(12),
+              static_cast<uint32_t>(13), static_cast<uint32_t>(14));
+  EXPECT_EQ(static_cast<uint32_t>(cmds::GetFragDataIndexEXT::kCmdId),
+            cmd.header.command);
+  EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+  EXPECT_EQ(static_cast<GLuint>(11), cmd.program);
+  EXPECT_EQ(static_cast<uint32_t>(12), cmd.name_bucket_id);
+  EXPECT_EQ(static_cast<uint32_t>(13), cmd.index_shm_id);
+  EXPECT_EQ(static_cast<uint32_t>(14), cmd.index_shm_offset);
+  CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
+}
+
 #endif  // GPU_COMMAND_BUFFER_COMMON_GLES2_CMD_FORMAT_TEST_AUTOGEN_H_
diff --git a/gpu/command_buffer/common/gles2_cmd_ids_autogen.h b/gpu/command_buffer/common/gles2_cmd_ids_autogen.h
index 22e5b0a..38dad791 100644
--- a/gpu/command_buffer/common/gles2_cmd_ids_autogen.h
+++ b/gpu/command_buffer/common/gles2_cmd_ids_autogen.h
@@ -331,7 +331,10 @@
   OP(BindFragmentInputLocationCHROMIUMBucket)     /* 572 */ \
   OP(ProgramPathFragmentInputGenCHROMIUM)         /* 573 */ \
   OP(BlendBarrierKHR)                             /* 574 */ \
-  OP(ApplyScreenSpaceAntialiasingCHROMIUM)        /* 575 */
+  OP(ApplyScreenSpaceAntialiasingCHROMIUM)        /* 575 */ \
+  OP(BindFragDataLocationIndexedEXTBucket)        /* 576 */ \
+  OP(BindFragDataLocationEXTBucket)               /* 577 */ \
+  OP(GetFragDataIndexEXT)                         /* 578 */
 
 enum CommandId {
   kStartPoint = cmd::kLastCommonId,  // All GLES2 commands start after this.
diff --git a/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h b/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h
index b84fbb0..af31a510 100644
--- a/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h
+++ b/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h
@@ -643,6 +643,9 @@
         0x78FB, "GL_RGB_YCBCR_422_CHROMIUM",
     },
     {
+        0x78FC, "GL_RGB_YCBCR_420V_CHROMIUM",
+    },
+    {
         0x80000000, "GL_MULTISAMPLE_BUFFER_BIT7_QCOM",
     },
     {
@@ -1279,6 +1282,9 @@
         0x8576, "GL_CONSTANT_CHROMIUM",
     },
     {
+        0x8589, "GL_SRC1_ALPHA_EXT",
+    },
+    {
         0x85B5, "GL_VERTEX_ARRAY_BINDING_OES",
     },
     {
@@ -1555,6 +1561,18 @@
         0x88F0, "GL_DEPTH24_STENCIL8_OES",
     },
     {
+        0x88F9, "GL_SRC1_COLOR_EXT",
+    },
+    {
+        0x88FA, "GL_ONE_MINUS_SRC1_COLOR_EXT",
+    },
+    {
+        0x88FB, "GL_ONE_MINUS_SRC1_ALPHA_EXT",
+    },
+    {
+        0x88FC, "GL_MAX_DUAL_SOURCE_DRAW_BUFFERS_EXT",
+    },
+    {
         0x88FD, "GL_VERTEX_ATTRIB_ARRAY_INTEGER",
     },
     {
@@ -3956,6 +3974,7 @@
       {GL_RGB, "GL_RGB"},
       {GL_RGB_YUV_420_CHROMIUM, "GL_RGB_YUV_420_CHROMIUM"},
       {GL_RGB_YCBCR_422_CHROMIUM, "GL_RGB_YCBCR_422_CHROMIUM"},
+      {GL_RGB_YCBCR_420V_CHROMIUM, "GL_RGB_YCBCR_420V_CHROMIUM"},
       {GL_RGBA, "GL_RGBA"},
   };
   return GLES2Util::GetQualifiedEnumString(string_table,
diff --git a/gpu/command_buffer/service/context_group.cc b/gpu/command_buffer/service/context_group.cc
index aeae5c65..cdda09f4 100644
--- a/gpu/command_buffer/service/context_group.cc
+++ b/gpu/command_buffer/service/context_group.cc
@@ -67,6 +67,7 @@
       max_vertex_uniform_vectors_(0u),
       max_color_attachments_(1u),
       max_draw_buffers_(1u),
+      max_dual_source_draw_buffers_(0u),
       program_cache_(NULL),
       feature_info_(feature_info) {
   {
@@ -139,6 +140,11 @@
     if (max_draw_buffers_ < 1)
       max_draw_buffers_ = 1;
   }
+  if (feature_info_->feature_flags().ext_blend_func_extended) {
+    GetIntegerv(GL_MAX_DUAL_SOURCE_DRAW_BUFFERS_EXT,
+                &max_dual_source_draw_buffers_);
+    DCHECK(max_dual_source_draw_buffers_ >= 1);
+  }
 
   buffer_manager_.reset(
       new BufferManager(memory_tracker_.get(), feature_info_.get()));
@@ -285,8 +291,9 @@
 
   path_manager_.reset(new PathManager());
 
-  program_manager_.reset(new ProgramManager(
-      program_cache_, max_varying_vectors_, feature_info_.get()));
+  program_manager_.reset(
+      new ProgramManager(program_cache_, max_varying_vectors_,
+                         max_dual_source_draw_buffers_, feature_info_.get()));
 
   if (!texture_manager_->Initialize()) {
     LOG(ERROR) << "Context::Group::Initialize failed because texture manager "
diff --git a/gpu/command_buffer/service/context_group.h b/gpu/command_buffer/service/context_group.h
index ad2c5df..fa9d3ac5 100644
--- a/gpu/command_buffer/service/context_group.h
+++ b/gpu/command_buffer/service/context_group.h
@@ -123,6 +123,10 @@
     return max_draw_buffers_;
   }
 
+  uint32 max_dual_source_draw_buffers() const {
+    return max_dual_source_draw_buffers_;
+  }
+
   FeatureInfo* feature_info() {
     return feature_info_.get();
   }
@@ -271,6 +275,7 @@
   uint32 max_vertex_uniform_vectors_;
   uint32 max_color_attachments_;
   uint32 max_draw_buffers_;
+  uint32 max_dual_source_draw_buffers_;
 
   ProgramCache* program_cache_;
 
diff --git a/gpu/command_buffer/service/disk_cache_proto.proto b/gpu/command_buffer/service/disk_cache_proto.proto
index b1059a6..6d78f4b9 100644
--- a/gpu/command_buffer/service/disk_cache_proto.proto
+++ b/gpu/command_buffer/service/disk_cache_proto.proto
@@ -27,11 +27,17 @@
   optional bool is_invariant = 3;
 }
 
+message ShaderOutputVariableProto {
+  optional ShaderVariableProto basic = 1;
+  optional int32 location = 2;
+}
+
 message ShaderProto {
   optional bytes sha = 1;
   repeated ShaderAttributeProto attribs = 2;
   repeated ShaderUniformProto uniforms = 3;
   repeated ShaderVaryingProto varyings = 4;
+  repeated ShaderOutputVariableProto output_variables = 5;
 }
 
 message GpuProgramProto {
diff --git a/gpu/command_buffer/service/feature_info.cc b/gpu/command_buffer/service/feature_info.cc
index c55ad26..76494a6 100644
--- a/gpu/command_buffer/service/feature_info.cc
+++ b/gpu/command_buffer/service/feature_info.cc
@@ -171,11 +171,13 @@
       blend_equation_advanced(false),
       blend_equation_advanced_coherent(false),
       ext_texture_rg(false),
+      chromium_image_ycbcr_420v(false),
       chromium_image_ycbcr_422(false),
       enable_subscribe_uniform(false),
       emulate_primitive_restart_fixed_index(false),
       ext_render_buffer_format_bgra8888(false),
-      ext_multisample_compatibility(false) {}
+      ext_multisample_compatibility(false),
+      ext_blend_func_extended(false) {}
 
 FeatureInfo::Workarounds::Workarounds() :
 #define GPU_OP(type, name) name(false),
@@ -225,7 +227,8 @@
 
   // The shader translator is needed to translate from WebGL-conformant GLES SL
   // to normal GLES SL, enforce WebGL conformance, translate from GLES SL 1.0 to
-  // target context GLSL, etc.
+  // target context GLSL, implement emulation of OpenGL ES features on OpenGL,
+  // etc.
   // The flag here is for testing only.
   disable_shader_translator_ =
       command_line->HasSwitch(switches::kDisableGLSLTranslator);
@@ -903,6 +906,8 @@
 
 #if defined(OS_MACOSX)
   AddExtensionString("GL_CHROMIUM_iosurface");
+  AddExtensionString("GL_CHROMIUM_ycbcr_420v_image");
+  feature_flags_.chromium_image_ycbcr_420v = true;
 #endif
 
   if (extensions.Contains("GL_APPLE_ycbcr_422")) {
@@ -1183,6 +1188,36 @@
   }
   UMA_HISTOGRAM_BOOLEAN("GPU.TextureRG", feature_flags_.ext_texture_rg);
 
+  bool has_opengl_dual_source_blending =
+      gl_version_info_->IsAtLeastGL(3, 3) ||
+      (gl_version_info_->IsAtLeastGL(3, 2) &&
+       extensions.Contains("GL_ARB_blend_func_extended"));
+  if (!disable_shader_translator_ &&
+      ((gl_version_info_->IsAtLeastGL(3, 2) &&
+        has_opengl_dual_source_blending) ||
+       (gl_version_info_->IsAtLeastGLES(3, 0) &&
+        extensions.Contains("GL_EXT_blend_func_extended")))) {
+    // Note: to simplify the code, we do not expose EXT_blend_func_extended
+    // unless the service context supports ES 3.0. This means the theoretical ES
+    // 2.0 implementation with EXT_blend_func_extended is not sufficient.
+    feature_flags_.ext_blend_func_extended = true;
+    AddExtensionString("GL_EXT_blend_func_extended");
+
+    // NOTE: SRC_ALPHA_SATURATE is valid for ES2 src blend factor.
+    // SRC_ALPHA_SATURATE is valid for ES3 src and dst blend factor.
+    validators_.dst_blend_factor.AddValue(GL_SRC_ALPHA_SATURATE_EXT);
+
+    validators_.src_blend_factor.AddValue(GL_SRC1_ALPHA_EXT);
+    validators_.dst_blend_factor.AddValue(GL_SRC1_ALPHA_EXT);
+    validators_.src_blend_factor.AddValue(GL_SRC1_COLOR_EXT);
+    validators_.dst_blend_factor.AddValue(GL_SRC1_COLOR_EXT);
+    validators_.src_blend_factor.AddValue(GL_ONE_MINUS_SRC1_COLOR_EXT);
+    validators_.dst_blend_factor.AddValue(GL_ONE_MINUS_SRC1_COLOR_EXT);
+    validators_.src_blend_factor.AddValue(GL_ONE_MINUS_SRC1_ALPHA_EXT);
+    validators_.dst_blend_factor.AddValue(GL_ONE_MINUS_SRC1_ALPHA_EXT);
+    validators_.g_l_state.AddValue(GL_MAX_DUAL_SOURCE_DRAW_BUFFERS_EXT);
+  }
+
 #if !defined(OS_MACOSX)
   if (workarounds_.ignore_egl_sync_failures) {
     gfx::GLFenceEGL::SetIgnoreFailures();
diff --git a/gpu/command_buffer/service/feature_info.h b/gpu/command_buffer/service/feature_info.h
index 3258bdf..f372f02 100644
--- a/gpu/command_buffer/service/feature_info.h
+++ b/gpu/command_buffer/service/feature_info.h
@@ -81,11 +81,13 @@
     bool blend_equation_advanced;
     bool blend_equation_advanced_coherent;
     bool ext_texture_rg;
+    bool chromium_image_ycbcr_420v;
     bool chromium_image_ycbcr_422;
     bool enable_subscribe_uniform;
     bool emulate_primitive_restart_fixed_index;
     bool ext_render_buffer_format_bgra8888;
     bool ext_multisample_compatibility;
+    bool ext_blend_func_extended;
   };
 
   struct Workarounds {
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index 34ddc02..1dec5cf 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -294,13 +294,10 @@
   return false;
 }
 
-static bool StringIsValidForGLES(const char* str) {
-  for (; *str; ++str) {
-    if (!CharacterIsValidForGLES(*str)) {
-      return false;
-    }
-  }
-  return true;
+static bool StringIsValidForGLES(const std::string& str) {
+  return str.length() == 0 ||
+         std::find_if_not(str.begin(), str.end(), CharacterIsValidForGLES) ==
+             str.end();
 }
 
 // This class prevents any GL errors that occur when it is in scope from
@@ -1200,9 +1197,22 @@
         client_id, service_id, group_->max_vertex_attribs(), client_visible);
   }
 
-  void DoBindAttribLocation(GLuint client_id, GLuint index, const char* name);
-  void DoBindUniformLocationCHROMIUM(
-      GLuint client_id, GLint location, const char* name);
+  void DoBindAttribLocation(GLuint client_id,
+                            GLuint index,
+                            const std::string& name);
+
+  error::Error DoBindFragDataLocation(GLuint program_id,
+                                      GLuint colorName,
+                                      const std::string& name);
+
+  error::Error DoBindFragDataLocationIndexed(GLuint program_id,
+                                             GLuint colorName,
+                                             GLuint index,
+                                             const std::string& name);
+
+  void DoBindUniformLocationCHROMIUM(GLuint client_id,
+                                     GLint location,
+                                     const std::string& name);
 
   error::Error GetAttribLocationHelper(
       GLuint client_id, uint32 location_shm_id, uint32 location_shm_offset,
@@ -1216,6 +1226,11 @@
       GLuint client_id, uint32 location_shm_id, uint32 location_shm_offset,
       const std::string& name_str);
 
+  error::Error GetFragDataIndexHelper(GLuint program_id,
+                                      uint32 index_shm_id,
+                                      uint32 index_shm_offset,
+                                      const std::string& name_str);
+
   // Wrapper for glShaderSource.
   void DoShaderSource(
       GLuint client_id, GLsizei count, const char** data, const GLint* length);
@@ -1859,7 +1874,8 @@
 
   void DoBindFragmentInputLocationCHROMIUM(GLuint program_id,
                                            GLint location,
-                                           const char* name);
+                                           const std::string& name);
+
   // Generate a member function prototype for each command in an automated and
   // typesafe way.
 #define GLES2_CMD_OP(name) \
@@ -3178,6 +3194,7 @@
   resources.MaxDrawBuffers = group_->max_draw_buffers();
   resources.MaxExpressionComplexity = 256;
   resources.MaxCallStackDepth = 256;
+  resources.MaxDualSourceDrawBuffers = group_->max_dual_source_draw_buffers();
 
   GLint range[2] = { 0, 0 };
   GLint precision = 0;
@@ -3210,6 +3227,8 @@
         features().ext_shader_texture_lod ? 1 : 0;
     resources.NV_draw_buffers =
         features().nv_draw_buffers ? 1 : 0;
+    resources.EXT_blend_func_extended =
+        features().ext_blend_func_extended ? 1 : 0;
   }
 
   ShShaderSpec shader_spec;
@@ -5485,6 +5504,12 @@
         params[0] = group_->bind_generates_resource() ? 1 : 0;
       }
       return true;
+    case GL_MAX_DUAL_SOURCE_DRAW_BUFFERS_EXT:
+      *num_written = 1;
+      if (params) {
+        params[0] = group_->max_dual_source_draw_buffers();
+      }
+      return true;
     default:
       if (pname >= GL_DRAW_BUFFER0_ARB &&
           pname < GL_DRAW_BUFFER0_ARB + group_->max_draw_buffers()) {
@@ -5614,14 +5639,15 @@
       &state_, target, pname, params);
 }
 
-void GLES2DecoderImpl::DoBindAttribLocation(
-    GLuint program_id, GLuint index, const char* name) {
+void GLES2DecoderImpl::DoBindAttribLocation(GLuint program_id,
+                                            GLuint index,
+                                            const std::string& name) {
   if (!StringIsValidForGLES(name)) {
     LOCAL_SET_GL_ERROR(
         GL_INVALID_VALUE, "glBindAttribLocation", "Invalid character");
     return;
   }
-  if (ProgramManager::IsInvalidPrefix(name, strlen(name))) {
+  if (ProgramManager::HasBuiltInPrefix(name)) {
     LOCAL_SET_GL_ERROR(
         GL_INVALID_OPERATION, "glBindAttribLocation", "reserved prefix");
     return;
@@ -5643,7 +5669,7 @@
   // Program::ExecuteBindAttribLocationCalls() right before link.
   program->SetAttribLocationBinding(name, static_cast<GLint>(index));
   // TODO(zmo): Get rid of the following glBindAttribLocation call.
-  glBindAttribLocation(program->service_id(), index, name);
+  glBindAttribLocation(program->service_id(), index, name.c_str());
 }
 
 error::Error GLES2DecoderImpl::HandleBindAttribLocationBucket(
@@ -5661,19 +5687,121 @@
   if (!bucket->GetAsString(&name_str)) {
     return error::kInvalidArguments;
   }
-  DoBindAttribLocation(program, index, name_str.c_str());
+  DoBindAttribLocation(program, index, name_str);
   return error::kNoError;
 }
 
-void GLES2DecoderImpl::DoBindUniformLocationCHROMIUM(
-    GLuint program_id, GLint location, const char* name) {
+error::Error GLES2DecoderImpl::DoBindFragDataLocation(GLuint program_id,
+                                                      GLuint colorName,
+                                                      const std::string& name) {
+  const char kFunctionName[] = "glBindFragDataLocationEXT";
+  if (!StringIsValidForGLES(name)) {
+    LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, kFunctionName, "invalid character");
+    return error::kNoError;
+  }
+  if (ProgramManager::HasBuiltInPrefix(name)) {
+    LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, kFunctionName, "reserved prefix");
+    return error::kNoError;
+  }
+  if (colorName >= group_->max_draw_buffers()) {
+    LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, kFunctionName,
+                       "colorName out of range");
+    return error::kNoError;
+  }
+  Program* program = GetProgramInfoNotShader(program_id, kFunctionName);
+  if (!program) {
+    return error::kNoError;
+  }
+  program->SetProgramOutputLocationBinding(name, colorName);
+  return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleBindFragDataLocationEXTBucket(
+    uint32 immediate_data_size,
+    const void* cmd_data) {
+  if (!features().ext_blend_func_extended) {
+    return error::kUnknownCommand;
+  }
+  const gles2::cmds::BindFragDataLocationEXTBucket& c =
+      *static_cast<const gles2::cmds::BindFragDataLocationEXTBucket*>(cmd_data);
+  GLuint program = static_cast<GLuint>(c.program);
+  GLuint colorNumber = static_cast<GLuint>(c.colorNumber);
+  Bucket* bucket = GetBucket(c.name_bucket_id);
+  if (!bucket || bucket->size() == 0) {
+    return error::kInvalidArguments;
+  }
+  std::string name_str;
+  if (!bucket->GetAsString(&name_str)) {
+    return error::kInvalidArguments;
+  }
+  return DoBindFragDataLocation(program, colorNumber, name_str);
+}
+
+error::Error GLES2DecoderImpl::DoBindFragDataLocationIndexed(
+    GLuint program_id,
+    GLuint colorName,
+    GLuint index,
+    const std::string& name) {
+  const char kFunctionName[] = "glBindFragDataLocationIndexEXT";
+  if (!StringIsValidForGLES(name)) {
+    LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, kFunctionName, "invalid character");
+    return error::kNoError;
+  }
+  if (ProgramManager::HasBuiltInPrefix(name)) {
+    LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, kFunctionName, "reserved prefix");
+    return error::kNoError;
+  }
+  if (index != 0 && index != 1) {
+    LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, kFunctionName, "index out of range");
+    return error::kNoError;
+  }
+  if ((index == 0 && colorName >= group_->max_draw_buffers()) ||
+      (index == 1 && colorName >= group_->max_dual_source_draw_buffers())) {
+    LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, kFunctionName,
+                       "colorName out of range for the color index");
+    return error::kNoError;
+  }
+  Program* program = GetProgramInfoNotShader(program_id, kFunctionName);
+  if (!program) {
+    return error::kNoError;
+  }
+  program->SetProgramOutputLocationIndexedBinding(name, colorName, index);
+  return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleBindFragDataLocationIndexedEXTBucket(
+    uint32 immediate_data_size,
+    const void* cmd_data) {
+  if (!features().ext_blend_func_extended) {
+    return error::kUnknownCommand;
+  }
+  const gles2::cmds::BindFragDataLocationIndexedEXTBucket& c =
+      *static_cast<const gles2::cmds::BindFragDataLocationIndexedEXTBucket*>(
+          cmd_data);
+  GLuint program = static_cast<GLuint>(c.program);
+  GLuint colorNumber = static_cast<GLuint>(c.colorNumber);
+  GLuint index = static_cast<GLuint>(c.index);
+  Bucket* bucket = GetBucket(c.name_bucket_id);
+  if (!bucket || bucket->size() == 0) {
+    return error::kInvalidArguments;
+  }
+  std::string name_str;
+  if (!bucket->GetAsString(&name_str)) {
+    return error::kInvalidArguments;
+  }
+  return DoBindFragDataLocationIndexed(program, colorNumber, index, name_str);
+}
+
+void GLES2DecoderImpl::DoBindUniformLocationCHROMIUM(GLuint program_id,
+                                                     GLint location,
+                                                     const std::string& name) {
   if (!StringIsValidForGLES(name)) {
     LOCAL_SET_GL_ERROR(
         GL_INVALID_VALUE,
         "glBindUniformLocationCHROMIUM", "Invalid character");
     return;
   }
-  if (ProgramManager::IsInvalidPrefix(name, strlen(name))) {
+  if (ProgramManager::HasBuiltInPrefix(name)) {
     LOCAL_SET_GL_ERROR(
         GL_INVALID_OPERATION,
         "glBindUniformLocationCHROMIUM", "reserved prefix");
@@ -5715,7 +5843,7 @@
   if (!bucket->GetAsString(&name_str)) {
     return error::kInvalidArguments;
   }
-  DoBindUniformLocationCHROMIUM(program, location, name_str.c_str());
+  DoBindUniformLocationCHROMIUM(program, location, name_str);
   return error::kNoError;
 }
 
@@ -9360,7 +9488,7 @@
 error::Error GLES2DecoderImpl::GetAttribLocationHelper(
     GLuint client_id, uint32 location_shm_id, uint32 location_shm_offset,
     const std::string& name_str) {
-  if (!StringIsValidForGLES(name_str.c_str())) {
+  if (!StringIsValidForGLES(name_str)) {
     LOCAL_SET_GL_ERROR(
         GL_INVALID_VALUE, "glGetAttribLocation", "Invalid character");
     return error::kNoError;
@@ -9408,7 +9536,7 @@
 error::Error GLES2DecoderImpl::GetUniformLocationHelper(
     GLuint client_id, uint32 location_shm_id, uint32 location_shm_offset,
     const std::string& name_str) {
-  if (!StringIsValidForGLES(name_str.c_str())) {
+  if (!StringIsValidForGLES(name_str)) {
     LOCAL_SET_GL_ERROR(
         GL_INVALID_VALUE, "glGetUniformLocation", "Invalid character");
     return error::kNoError;
@@ -9508,6 +9636,7 @@
 error::Error GLES2DecoderImpl::GetFragDataLocationHelper(
     GLuint client_id, uint32 location_shm_id, uint32 location_shm_offset,
     const std::string& name_str) {
+  const char kFunctionName[] = "glGetFragDataLocation";
   GLint* location = GetSharedMemoryAs<GLint*>(
       location_shm_id, location_shm_offset, sizeof(GLint));
   if (!location) {
@@ -9517,12 +9646,17 @@
   if (*location != -1) {
     return error::kInvalidArguments;
   }
-  Program* program = GetProgramInfoNotShader(
-      client_id, "glGetFragDataLocation");
+  Program* program = GetProgramInfoNotShader(client_id, kFunctionName);
   if (!program) {
     return error::kNoError;
   }
-  *location = glGetFragDataLocation(program->service_id(), name_str.c_str());
+  if (!program->IsValid()) {
+    LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, kFunctionName,
+                       "program not linked");
+    return error::kNoError;
+  }
+
+  *location = program->GetFragDataLocation(name_str);
   return error::kNoError;
 }
 
@@ -9545,6 +9679,55 @@
       c.program, c.location_shm_id, c.location_shm_offset, name_str);
 }
 
+error::Error GLES2DecoderImpl::GetFragDataIndexHelper(
+    GLuint program_id,
+    uint32 index_shm_id,
+    uint32 index_shm_offset,
+    const std::string& name_str) {
+  const char kFunctionName[] = "glGetFragDataIndexEXT";
+  GLint* index =
+      GetSharedMemoryAs<GLint*>(index_shm_id, index_shm_offset, sizeof(GLint));
+  if (!index) {
+    return error::kOutOfBounds;
+  }
+  // Check that the client initialized the result.
+  if (*index != -1) {
+    return error::kInvalidArguments;
+  }
+  Program* program = GetProgramInfoNotShader(program_id, kFunctionName);
+  if (!program) {
+    return error::kNoError;
+  }
+  if (!program->IsValid()) {
+    LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, kFunctionName,
+                       "program not linked");
+    return error::kNoError;
+  }
+
+  *index = program->GetFragDataIndex(name_str);
+  return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleGetFragDataIndexEXT(
+    uint32 immediate_data_size,
+    const void* cmd_data) {
+  if (!features().ext_blend_func_extended) {
+    return error::kUnknownCommand;
+  }
+  const gles2::cmds::GetFragDataIndexEXT& c =
+      *static_cast<const gles2::cmds::GetFragDataIndexEXT*>(cmd_data);
+  Bucket* bucket = GetBucket(c.name_bucket_id);
+  if (!bucket) {
+    return error::kInvalidArguments;
+  }
+  std::string name_str;
+  if (!bucket->GetAsString(&name_str)) {
+    return error::kInvalidArguments;
+  }
+  return GetFragDataIndexHelper(c.program, c.index_shm_id, c.index_shm_offset,
+                                name_str);
+}
+
 error::Error GLES2DecoderImpl::HandleGetUniformBlockIndex(
     uint32 immediate_data_size, const void* cmd_data) {
   if (!unsafe_es3_apis_enabled())
@@ -15288,23 +15471,24 @@
   return error::kNoError;
 }
 
-void GLES2DecoderImpl::DoBindFragmentInputLocationCHROMIUM(GLuint program_id,
-                                                           GLint location,
-                                                           const char* name) {
+void GLES2DecoderImpl::DoBindFragmentInputLocationCHROMIUM(
+    GLuint program_id,
+    GLint location,
+    const std::string& name) {
   static const char kFunctionName[] = "glBindFragmentInputLocationCHROMIUM";
-  Program* program = GetProgram(program_id);
-  if (!program || program->IsDeleted()) {
-    LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, kFunctionName, "invalid program");
-    return;
-  }
   if (!StringIsValidForGLES(name)) {
     LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, kFunctionName, "invalid character");
     return;
   }
-  if (ProgramManager::IsInvalidPrefix(name, strlen(name))) {
+  if (ProgramManager::HasBuiltInPrefix(name)) {
     LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, kFunctionName, "reserved prefix");
     return;
   }
+  Program* program = GetProgram(program_id);
+  if (!program || program->IsDeleted()) {
+    LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, kFunctionName, "invalid program");
+    return;
+  }
   if (location < 0 ||
       static_cast<uint32>(location) >= group_->max_varying_vectors() * 4) {
     LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, kFunctionName,
@@ -15335,7 +15519,7 @@
   if (!bucket->GetAsString(&name_str)) {
     return error::kInvalidArguments;
   }
-  DoBindFragmentInputLocationCHROMIUM(program, location, name_str.c_str());
+  DoBindFragmentInputLocationCHROMIUM(program, location, name_str);
   return error::kNoError;
 }
 
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc
index 3f6d20d..c09c658 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc
@@ -1533,6 +1533,17 @@
   EXPECT_EQ(entries_per_cmd_ + cmds_[1].header.size, num_processed);
 }
 
+void GLES3DecoderWithESSL3ShaderTest::SetUp() {
+  base::CommandLine command_line(0, nullptr);
+  command_line.AppendSwitch(switches::kEnableUnsafeES3APIs);
+  InitState init;
+  init.gl_version = "OpenGL ES 3.0";
+  init.bind_generates_resource = true;
+  init.context_type = CONTEXT_TYPE_OPENGLES3;
+  InitDecoderWithCommandLine(init, &command_line);
+  SetupDefaultProgram();
+}
+
 INSTANTIATE_TEST_CASE_P(Service, GLES2DecoderTest, ::testing::Bool());
 
 INSTANTIATE_TEST_CASE_P(Service, GLES2DecoderWithShaderTest, ::testing::Bool());
@@ -1547,5 +1558,9 @@
 
 INSTANTIATE_TEST_CASE_P(Service, GLES3DecoderTest, ::testing::Bool());
 
+INSTANTIATE_TEST_CASE_P(Service,
+                        GLES3DecoderWithESSL3ShaderTest,
+                        ::testing::Bool());
+
 }  // namespace gles2
 }  // namespace gpu
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.h b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.h
index a57903c..4cab05c 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.h
@@ -82,6 +82,12 @@
   void SetUp() override;
 };
 
+class GLES3DecoderWithESSL3ShaderTest : public GLES2DecoderWithShaderTestBase {
+ public:
+  GLES3DecoderWithESSL3ShaderTest() { shader_language_version_ = 300; }
+  void SetUp() override;
+};
+
 }  // namespace gles2
 }  // namespace gpu
 
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc
index c704c285..b149135 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc
@@ -120,7 +120,8 @@
       cached_color_mask_alpha_(true),
       cached_depth_mask_(true),
       cached_stencil_front_mask_(static_cast<GLuint>(-1)),
-      cached_stencil_back_mask_(static_cast<GLuint>(-1)) {
+      cached_stencil_back_mask_(static_cast<GLuint>(-1)),
+      shader_language_version_(100) {
   memset(immediate_buffer_, 0xEE, sizeof(immediate_buffer_));
 }
 
@@ -1498,7 +1499,10 @@
 const GLenum GLES2DecoderTestBase::kUniformCubemapType;
 const GLint GLES2DecoderTestBase::kInvalidUniformLocation;
 const GLint GLES2DecoderTestBase::kBadUniformIndex;
-
+const GLint GLES2DecoderTestBase::kOutputVariable1Size;
+const GLenum GLES2DecoderTestBase::kOutputVariable1Type;
+const GLuint GLES2DecoderTestBase::kOutputVariable1ColorName;
+const GLuint GLES2DecoderTestBase::kOutputVariable1Index;
 #endif
 
 const char* GLES2DecoderTestBase::kAttrib1Name = "attrib1";
@@ -1512,6 +1516,9 @@
 const char* GLES2DecoderTestBase::kUniform6Name = "uniform6";
 const char* GLES2DecoderTestBase::kUniform7Name = "uniform7";
 
+const char* GLES2DecoderTestBase::kOutputVariable1Name = "gl_FragColor";
+const char* GLES2DecoderTestBase::kOutputVariable1NameESSL3 = "color";
+
 void GLES2DecoderTestBase::SetupDefaultProgram() {
   {
     static AttribInfo attribs[] = {
@@ -1660,6 +1667,19 @@
     GLuint program_client_id, GLuint program_service_id,
     GLuint vertex_shader_client_id, GLuint vertex_shader_service_id,
     GLuint fragment_shader_client_id, GLuint fragment_shader_service_id) {
+  static TestHelper::ProgramOutputInfo kProgramOutputsESSL1[] = {{
+      kOutputVariable1Name, kOutputVariable1Size, kOutputVariable1Type,
+      kOutputVariable1ColorName, kOutputVariable1Index,
+  }};
+  static TestHelper::ProgramOutputInfo kProgramOutputsESSL3[] = {{
+      kOutputVariable1NameESSL3, kOutputVariable1Size, kOutputVariable1Type,
+      kOutputVariable1ColorName, kOutputVariable1Index,
+  }};
+  TestHelper::ProgramOutputInfo* program_outputs =
+      shader_language_version_ == 100 ? kProgramOutputsESSL1
+                                      : kProgramOutputsESSL3;
+  const size_t kNumProgramOutputs = 1;
+
   {
     InSequence s;
 
@@ -1671,9 +1691,11 @@
                 AttachShader(program_service_id, fragment_shader_service_id))
         .Times(1)
         .RetiresOnSaturation();
-    TestHelper::SetupShaderExpectations(gl_.get(), group_->feature_info(),
-                                        attribs, num_attribs, uniforms,
-                                        num_uniforms, program_service_id);
+
+    TestHelper::SetupShaderExpectationsWithVaryings(
+        gl_.get(), group_->feature_info(), attribs, num_attribs, uniforms,
+        num_uniforms, nullptr, 0, program_outputs, kNumProgramOutputs,
+        program_service_id);
   }
 
   DoCreateShader(
@@ -1682,10 +1704,20 @@
       GL_FRAGMENT_SHADER, fragment_shader_client_id,
       fragment_shader_service_id);
 
-  TestHelper::SetShaderStates(
-      gl_.get(), GetShader(vertex_shader_client_id), true);
-  TestHelper::SetShaderStates(
-      gl_.get(), GetShader(fragment_shader_client_id), true);
+  TestHelper::SetShaderStates(gl_.get(), GetShader(vertex_shader_client_id),
+                              true, nullptr, nullptr, &shader_language_version_,
+                              nullptr, nullptr, nullptr, nullptr, nullptr,
+                              nullptr);
+
+  OutputVariableList frag_output_variable_list;
+  frag_output_variable_list.push_back(TestHelper::ConstructOutputVariable(
+      program_outputs[0].type, program_outputs[0].size, GL_MEDIUM_FLOAT, true,
+      program_outputs[0].name));
+
+  TestHelper::SetShaderStates(gl_.get(), GetShader(fragment_shader_client_id),
+                              true, nullptr, nullptr, &shader_language_version_,
+                              nullptr, nullptr, nullptr, nullptr,
+                              &frag_output_variable_list, nullptr);
 
   cmds::AttachShader attach_cmd;
   attach_cmd.Init(program_client_id, vertex_shader_client_id);
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h
index d19937d9..7746969 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h
@@ -584,6 +584,13 @@
   static const GLint kInvalidUniformLocation = 30;
   static const GLint kBadUniformIndex = 1000;
 
+  static const GLint kOutputVariable1Size = 0;
+  static const GLenum kOutputVariable1Type = GL_FLOAT_VEC4;
+  static const GLuint kOutputVariable1ColorName = 7;
+  static const GLuint kOutputVariable1Index = 0;
+  static const char* kOutputVariable1Name;
+  static const char* kOutputVariable1NameESSL3;
+
   // Use StrictMock to make 100% sure we know how GL will be called.
   scoped_ptr< ::testing::StrictMock< ::gfx::MockGLInterface> > gl_;
   scoped_refptr<gfx::GLSurfaceStub> surface_;
@@ -642,6 +649,8 @@
 
   EnableFlags enable_flags_;
 
+  int shader_language_version_;
+
  private:
   class MockCommandBufferEngine : public CommandBufferEngine {
    public:
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_extensions.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_extensions.cc
index c0b6de5..d295183 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_extensions.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_extensions.cc
@@ -520,6 +520,26 @@
                         GLES2DecoderTestWithEXTMultisampleCompatibility,
                         ::testing::Bool());
 
+class GLES2DecoderTestWithBlendFuncExtended : public GLES2DecoderTest {
+ public:
+  GLES2DecoderTestWithBlendFuncExtended() {}
+  void SetUp() override {
+    InitState init;
+    init.gl_version = "opengl es 3.0";
+    init.has_alpha = true;
+    init.has_depth = true;
+    init.request_alpha = true;
+    init.request_depth = true;
+    init.bind_generates_resource = true;
+    init.extensions = "GL_EXT_blend_func_extended";
+    InitDecoder(init);
+  }
+};
+INSTANTIATE_TEST_CASE_P(Service,
+                        GLES2DecoderTestWithBlendFuncExtended,
+                        ::testing::Bool());
+
+
 TEST_P(GLES2DecoderTestWithCHROMIUMPathRendering, GenDeletePaths) {
   static GLuint kFirstClientID = client_path_id_ + 88;
   static GLsizei kPathCount = 58;
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_programs.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_programs.cc
index 8d675375..cb49ae9 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_programs.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_programs.cc
@@ -2016,27 +2016,22 @@
   EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
 }
 
-TEST_P(GLES2DecoderWithShaderTest, GetFragDataLocation) {
+TEST_P(GLES3DecoderWithESSL3ShaderTest, GetFragDataLocation) {
   const uint32 kBucketId = 123;
-  const GLint kLocation = 10;
-  const char* kName = "color";
   typedef GetFragDataLocation::Result Result;
   Result* result = GetSharedMemoryAs<Result*>();
-  SetBucketAsCString(kBucketId, kName);
+  SetBucketAsCString(kBucketId, kOutputVariable1NameESSL3);
   *result = -1;
   GetFragDataLocation cmd;
   cmd.Init(client_program_id_, kBucketId, kSharedMemoryId, kSharedMemoryOffset);
-  EXPECT_CALL(*gl_, GetFragDataLocation(kServiceProgramId, StrEq(kName)))
-      .WillOnce(Return(kLocation))
-      .RetiresOnSaturation();
   decoder_->set_unsafe_es3_apis_enabled(true);
   EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
-  EXPECT_EQ(kLocation, *result);
+  EXPECT_EQ(static_cast<GLint>(kOutputVariable1ColorName), *result);
   decoder_->set_unsafe_es3_apis_enabled(false);
   EXPECT_EQ(error::kUnknownCommand, ExecuteCmd(cmd));
 }
 
-TEST_P(GLES2DecoderWithShaderTest, GetFragDataLocationInvalidArgs) {
+TEST_P(GLES3DecoderWithESSL3ShaderTest, GetFragDataLocationInvalidArgs) {
   const uint32 kBucketId = 123;
   typedef GetFragDataLocation::Result Result;
   Result* result = GetSharedMemoryAs<Result*>();
diff --git a/gpu/command_buffer/service/gles2_cmd_validation_implementation_autogen.h b/gpu/command_buffer/service/gles2_cmd_validation_implementation_autogen.h
index 981d100..7a201b7 100644
--- a/gpu/command_buffer/service/gles2_cmd_validation_implementation_autogen.h
+++ b/gpu/command_buffer/service/gles2_cmd_validation_implementation_autogen.h
@@ -363,7 +363,11 @@
 };
 
 static const GLenum valid_image_internal_format_table[] = {
-    GL_RGB, GL_RGB_YUV_420_CHROMIUM, GL_RGB_YCBCR_422_CHROMIUM, GL_RGBA,
+    GL_RGB,
+    GL_RGB_YUV_420_CHROMIUM,
+    GL_RGB_YCBCR_422_CHROMIUM,
+    GL_RGB_YCBCR_420V_CHROMIUM,
+    GL_RGBA,
 };
 
 static const GLenum valid_image_usage_table[] = {
diff --git a/gpu/command_buffer/service/memory_program_cache.cc b/gpu/command_buffer/service/memory_program_cache.cc
index 74809a9..1841348 100644
--- a/gpu/command_buffer/service/memory_program_cache.cc
+++ b/gpu/command_buffer/service/memory_program_cache.cc
@@ -40,12 +40,6 @@
 
 namespace {
 
-enum ShaderMapType {
-  ATTRIB_MAP = 0,
-  UNIFORM_MAP,
-  VARYING_MAP
-};
-
 void FillShaderVariableProto(
     ShaderVariableProto* proto, const sh::ShaderVariable& variable) {
   proto->set_type(variable.type);
@@ -79,6 +73,12 @@
   proto->set_is_invariant(varying.isInvariant);
 }
 
+void FillShaderOutputVariableProto(ShaderOutputVariableProto* proto,
+                                   const sh::OutputVariable& attrib) {
+  FillShaderVariableProto(proto->mutable_basic(), attrib);
+  proto->set_location(attrib.location);
+}
+
 void FillShaderProto(ShaderProto* proto, const char* sha,
                      const Shader* shader) {
   proto->set_sha(sha, gpu::gles2::ProgramCache::kHashLength);
@@ -97,6 +97,11 @@
     ShaderVaryingProto* info = proto->add_varyings();
     FillShaderVaryingProto(info, iter->second);
   }
+  for (auto iter = shader->output_variable_list().begin();
+       iter != shader->output_variable_list().end(); ++iter) {
+    ShaderOutputVariableProto* info = proto->add_output_variables();
+    FillShaderOutputVariableProto(info, *iter);
+  }
 }
 
 void RetrieveShaderVariableInfo(
@@ -138,6 +143,14 @@
   (*map)[proto.basic().mapped_name()] = varying;
 }
 
+void RetrieveShaderOutputVariableInfo(const ShaderOutputVariableProto& proto,
+                                      OutputVariableList* list) {
+  sh::OutputVariable output_variable;
+  RetrieveShaderVariableInfo(proto.basic(), &output_variable);
+  output_variable.location = proto.location();
+  list->push_back(output_variable);
+}
+
 void RunShaderCallback(const ShaderCacheCallback& callback,
                        GpuProgramProto* proto,
                        std::string sha_string) {
@@ -213,9 +226,11 @@
   shader_a->set_attrib_map(value->attrib_map_0());
   shader_a->set_uniform_map(value->uniform_map_0());
   shader_a->set_varying_map(value->varying_map_0());
+  shader_a->set_output_variable_list(value->output_variable_list_0());
   shader_b->set_attrib_map(value->attrib_map_1());
   shader_b->set_uniform_map(value->uniform_map_1());
   shader_b->set_varying_map(value->varying_map_1());
+  shader_b->set_output_variable_list(value->output_variable_list_1());
 
   if (!shader_callback.is_null() &&
       !base::CommandLine::ForCurrentProcess()->HasSwitch(
@@ -302,20 +317,14 @@
     RunShaderCallback(shader_callback, proto.get(), sha_string);
   }
 
-  store_.Put(sha_string,
-             new ProgramCacheValue(length,
-                                   format,
-                                   binary.release(),
-                                   sha_string,
-                                   a_sha,
-                                   shader_a->attrib_map(),
-                                   shader_a->uniform_map(),
-                                   shader_a->varying_map(),
-                                   b_sha,
-                                   shader_b->attrib_map(),
-                                   shader_b->uniform_map(),
-                                   shader_b->varying_map(),
-                                   this));
+  store_.Put(
+      sha_string,
+      new ProgramCacheValue(
+          length, format, binary.release(), sha_string, a_sha,
+          shader_a->attrib_map(), shader_a->uniform_map(),
+          shader_a->varying_map(), shader_a->output_variable_list(), b_sha,
+          shader_b->attrib_map(), shader_b->uniform_map(),
+          shader_b->varying_map(), shader_b->output_variable_list(), this));
 
   UMA_HISTOGRAM_COUNTS("GPU.ProgramCache.MemorySizeAfterKb",
                        curr_size_bytes_ / 1024);
@@ -327,6 +336,7 @@
     AttributeMap vertex_attribs;
     UniformMap vertex_uniforms;
     VaryingMap vertex_varyings;
+    OutputVariableList vertex_output_variables;
     for (int i = 0; i < proto->vertex_shader().attribs_size(); i++) {
       RetrieveShaderAttributeInfo(proto->vertex_shader().attribs(i),
                                   &vertex_attribs);
@@ -339,10 +349,15 @@
       RetrieveShaderVaryingInfo(proto->vertex_shader().varyings(i),
                                 &vertex_varyings);
     }
+    for (int i = 0; i < proto->vertex_shader().output_variables_size(); i++) {
+      RetrieveShaderOutputVariableInfo(
+          proto->vertex_shader().output_variables(i), &vertex_output_variables);
+    }
 
     AttributeMap fragment_attribs;
     UniformMap fragment_uniforms;
     VaryingMap fragment_varyings;
+    OutputVariableList fragment_output_variables;
     for (int i = 0; i < proto->fragment_shader().attribs_size(); i++) {
       RetrieveShaderAttributeInfo(proto->fragment_shader().attribs(i),
                                   &fragment_attribs);
@@ -355,24 +370,24 @@
       RetrieveShaderVaryingInfo(proto->fragment_shader().varyings(i),
                                 &fragment_varyings);
     }
+    for (int i = 0; i < proto->fragment_shader().output_variables_size(); i++) {
+      RetrieveShaderOutputVariableInfo(
+          proto->fragment_shader().output_variables(i),
+          &fragment_output_variables);
+    }
 
     scoped_ptr<char[]> binary(new char[proto->program().length()]);
     memcpy(binary.get(), proto->program().c_str(), proto->program().length());
 
-    store_.Put(proto->sha(),
-               new ProgramCacheValue(proto->program().length(),
-                                     proto->format(),
-                                     binary.release(),
-                                     proto->sha(),
-                                     proto->vertex_shader().sha().c_str(),
-                                     vertex_attribs,
-                                     vertex_uniforms,
-                                     vertex_varyings,
-                                     proto->fragment_shader().sha().c_str(),
-                                     fragment_attribs,
-                                     fragment_uniforms,
-                                     fragment_varyings,
-                                     this));
+    store_.Put(
+        proto->sha(),
+        new ProgramCacheValue(
+            proto->program().length(), proto->format(), binary.release(),
+            proto->sha(), proto->vertex_shader().sha().c_str(), vertex_attribs,
+            vertex_uniforms, vertex_varyings, vertex_output_variables,
+            proto->fragment_shader().sha().c_str(), fragment_attribs,
+            fragment_uniforms, fragment_varyings, fragment_output_variables,
+            this));
 
     UMA_HISTOGRAM_COUNTS("GPU.ProgramCache.MemorySizeAfterKb",
                          curr_size_bytes_ / 1024);
@@ -390,10 +405,12 @@
     const AttributeMap& attrib_map_0,
     const UniformMap& uniform_map_0,
     const VaryingMap& varying_map_0,
+    const OutputVariableList& output_variable_list_0,
     const char* shader_1_hash,
     const AttributeMap& attrib_map_1,
     const UniformMap& uniform_map_1,
     const VaryingMap& varying_map_1,
+    const OutputVariableList& output_variable_list_1,
     MemoryProgramCache* program_cache)
     : length_(length),
       format_(format),
@@ -403,10 +420,12 @@
       attrib_map_0_(attrib_map_0),
       uniform_map_0_(uniform_map_0),
       varying_map_0_(varying_map_0),
+      output_variable_list_0_(output_variable_list_0),
       shader_1_hash_(shader_1_hash, kHashLength),
       attrib_map_1_(attrib_map_1),
       uniform_map_1_(uniform_map_1),
       varying_map_1_(varying_map_1),
+      output_variable_list_1_(output_variable_list_1),
       program_cache_(program_cache) {
   program_cache_->curr_size_bytes_ += length_;
   program_cache_->LinkedProgramCacheSuccess(program_hash);
diff --git a/gpu/command_buffer/service/memory_program_cache.h b/gpu/command_buffer/service/memory_program_cache.h
index 593625da..7e9b83dd 100644
--- a/gpu/command_buffer/service/memory_program_cache.h
+++ b/gpu/command_buffer/service/memory_program_cache.h
@@ -57,10 +57,12 @@
                       const AttributeMap& attrib_map_0,
                       const UniformMap& uniform_map_0,
                       const VaryingMap& varying_map_0,
+                      const OutputVariableList& output_variable_list_0,
                       const char* shader_1_hash,
                       const AttributeMap& attrib_map_1,
                       const UniformMap& uniform_map_1,
                       const VaryingMap& varying_map_1,
+                      const OutputVariableList& output_variable_list_1,
                       MemoryProgramCache* program_cache);
 
     GLsizei length() const {
@@ -91,6 +93,10 @@
       return varying_map_0_;
     }
 
+    const OutputVariableList& output_variable_list_0() const {
+      return output_variable_list_0_;
+    }
+
     const std::string& shader_1_hash() const {
       return shader_1_hash_;
     }
@@ -107,6 +113,10 @@
       return varying_map_1_;
     }
 
+    const OutputVariableList& output_variable_list_1() const {
+      return output_variable_list_1_;
+    }
+
    private:
     friend class base::RefCounted<ProgramCacheValue>;
 
@@ -120,10 +130,12 @@
     const AttributeMap attrib_map_0_;
     const UniformMap uniform_map_0_;
     const VaryingMap varying_map_0_;
+    const OutputVariableList output_variable_list_0_;
     const std::string shader_1_hash_;
     const AttributeMap attrib_map_1_;
     const UniformMap uniform_map_1_;
     const VaryingMap varying_map_1_;
+    const OutputVariableList output_variable_list_1_;
     MemoryProgramCache* const program_cache_;
 
     DISALLOW_COPY_AND_ASSIGN(ProgramCacheValue);
diff --git a/gpu/command_buffer/service/memory_program_cache_unittest.cc b/gpu/command_buffer/service/memory_program_cache_unittest.cc
index a005db95..f92860f2 100644
--- a/gpu/command_buffer/service/memory_program_cache_unittest.cc
+++ b/gpu/command_buffer/service/memory_program_cache_unittest.cc
@@ -100,9 +100,11 @@
     AttributeMap vertex_attrib_map;
     UniformMap vertex_uniform_map;
     VaryingMap vertex_varying_map;
+    OutputVariableList vertex_output_variable_list;
     AttributeMap fragment_attrib_map;
     UniformMap fragment_uniform_map;
     VaryingMap fragment_varying_map;
+    OutputVariableList fragment_output_variable_list;
 
     vertex_attrib_map["a"] = TestHelper::ConstructAttribute(
         GL_FLOAT_VEC2, 34, GL_LOW_FLOAT, false, "a");
@@ -112,24 +114,28 @@
         GL_FLOAT_VEC3, 3114, GL_HIGH_FLOAT, true, "b");
     vertex_varying_map["c"] = TestHelper::ConstructVarying(
         GL_FLOAT_VEC4, 2, GL_HIGH_FLOAT, true, "c");
+    vertex_output_variable_list.push_back(TestHelper::ConstructOutputVariable(
+        GL_FLOAT, 0, GL_HIGH_FLOAT, true, "d"));
     fragment_attrib_map["jjjbb"] = TestHelper::ConstructAttribute(
         GL_FLOAT_MAT4, 1114, GL_MEDIUM_FLOAT, false, "jjjbb");
     fragment_uniform_map["k"] = TestHelper::ConstructUniform(
         GL_FLOAT_MAT2, 34413, GL_MEDIUM_FLOAT, true, "k");
     fragment_varying_map["c"] = TestHelper::ConstructVarying(
         GL_FLOAT_VEC4, 2, GL_HIGH_FLOAT, true, "c");
+    fragment_output_variable_list.push_back(TestHelper::ConstructOutputVariable(
+        GL_FLOAT, 0, GL_HIGH_FLOAT, true, "d"));
 
     vertex_shader_->set_source("bbbalsldkdkdkd");
     fragment_shader_->set_source("bbbal   sldkdkdkas 134 ad");
 
+    TestHelper::SetShaderStates(gl_.get(), vertex_shader_, true, nullptr,
+                                nullptr, nullptr, &vertex_attrib_map,
+                                &vertex_uniform_map, &vertex_varying_map,
+                                nullptr, &vertex_output_variable_list, nullptr);
     TestHelper::SetShaderStates(
-        gl_.get(), vertex_shader_, true, NULL, NULL, NULL,
-        &vertex_attrib_map, &vertex_uniform_map, &vertex_varying_map,
-        NULL, NULL);
-    TestHelper::SetShaderStates(
-        gl_.get(), fragment_shader_, true, NULL, NULL, NULL,
+        gl_.get(), fragment_shader_, true, nullptr, nullptr, nullptr,
         &fragment_attrib_map, &fragment_uniform_map, &fragment_varying_map,
-        NULL, NULL);
+        nullptr, &fragment_output_variable_list, nullptr);
   }
 
   void SetExpectationsForSaveLinkedProgram(
@@ -254,17 +260,22 @@
   AttributeMap vertex_attrib_map = vertex_shader_->attrib_map();
   UniformMap vertex_uniform_map = vertex_shader_->uniform_map();
   VaryingMap vertex_varying_map = vertex_shader_->varying_map();
+  OutputVariableList vertex_output_variable_list =
+      vertex_shader_->output_variable_list();
   AttributeMap fragment_attrib_map = fragment_shader_->attrib_map();
   UniformMap fragment_uniform_map = fragment_shader_->uniform_map();
   VaryingMap fragment_varying_map = fragment_shader_->varying_map();
+  OutputVariableList fragment_output_variable_list =
+      fragment_shader_->output_variable_list();
 
   vertex_shader_->set_attrib_map(AttributeMap());
   vertex_shader_->set_uniform_map(UniformMap());
   vertex_shader_->set_varying_map(VaryingMap());
+  vertex_shader_->set_output_variable_list(OutputVariableList());
   fragment_shader_->set_attrib_map(AttributeMap());
   fragment_shader_->set_uniform_map(UniformMap());
   fragment_shader_->set_varying_map(VaryingMap());
-
+  fragment_shader_->set_output_variable_list(OutputVariableList());
   SetExpectationsForLoadLinkedProgram(kProgramId, &emulator);
 
   EXPECT_EQ(ProgramCache::PROGRAM_LOAD_SUCCESS, cache_->LoadLinkedProgram(
@@ -283,9 +294,13 @@
   EXPECT_EQ(vertex_attrib_map, vertex_shader_->attrib_map());
   EXPECT_EQ(vertex_uniform_map, vertex_shader_->uniform_map());
   EXPECT_EQ(vertex_varying_map, vertex_shader_->varying_map());
+  EXPECT_EQ(vertex_output_variable_list,
+            vertex_shader_->output_variable_list());
   EXPECT_EQ(fragment_attrib_map, fragment_shader_->attrib_map());
   EXPECT_EQ(fragment_uniform_map, fragment_shader_->uniform_map());
   EXPECT_EQ(fragment_varying_map, fragment_shader_->varying_map());
+  EXPECT_EQ(fragment_output_variable_list,
+            fragment_shader_->output_variable_list());
 #endif
 }
 
@@ -309,16 +324,22 @@
   AttributeMap vertex_attrib_map = vertex_shader_->attrib_map();
   UniformMap vertex_uniform_map = vertex_shader_->uniform_map();
   VaryingMap vertex_varying_map = vertex_shader_->varying_map();
+  OutputVariableList vertex_output_variable_list =
+      vertex_shader_->output_variable_list();
   AttributeMap fragment_attrib_map = fragment_shader_->attrib_map();
   UniformMap fragment_uniform_map = fragment_shader_->uniform_map();
   VaryingMap fragment_varying_map = fragment_shader_->varying_map();
+  OutputVariableList fragment_output_variable_list =
+      fragment_shader_->output_variable_list();
 
   vertex_shader_->set_attrib_map(AttributeMap());
   vertex_shader_->set_uniform_map(UniformMap());
   vertex_shader_->set_varying_map(VaryingMap());
+  vertex_shader_->set_output_variable_list(OutputVariableList());
   fragment_shader_->set_attrib_map(AttributeMap());
   fragment_shader_->set_uniform_map(UniformMap());
   fragment_shader_->set_varying_map(VaryingMap());
+  fragment_shader_->set_output_variable_list(OutputVariableList());
 
   SetExpectationsForLoadLinkedProgram(kProgramId, &emulator);
 
@@ -341,9 +362,13 @@
   EXPECT_EQ(vertex_attrib_map, vertex_shader_->attrib_map());
   EXPECT_EQ(vertex_uniform_map, vertex_shader_->uniform_map());
   EXPECT_EQ(vertex_varying_map, vertex_shader_->varying_map());
+  EXPECT_EQ(vertex_output_variable_list,
+            vertex_shader_->output_variable_list());
   EXPECT_EQ(fragment_attrib_map, fragment_shader_->attrib_map());
   EXPECT_EQ(fragment_uniform_map, fragment_shader_->uniform_map());
   EXPECT_EQ(fragment_varying_map, fragment_shader_->varying_map());
+  EXPECT_EQ(fragment_output_variable_list,
+            fragment_shader_->output_variable_list());
 #endif
 }
 
diff --git a/gpu/command_buffer/service/mocks.h b/gpu/command_buffer/service/mocks.h
index 2ef657f..a9a7efba 100644
--- a/gpu/command_buffer/service/mocks.h
+++ b/gpu/command_buffer/service/mocks.h
@@ -95,16 +95,17 @@
                     const ShBuiltInResources* resources,
                     ShShaderOutput shader_output_language,
                     ShCompileOptions driver_bug_workarounds));
-  MOCK_CONST_METHOD9(Translate, bool(
-      const std::string& shader_source,
-      std::string* info_log,
-      std::string* translated_source,
-      int* shader_version,
-      AttributeMap* attrib_map,
-      UniformMap* uniform_map,
-      VaryingMap* varying_map,
-      InterfaceBlockMap* interface_block_map,
-      NameMap* name_map));
+  MOCK_CONST_METHOD10(Translate,
+                      bool(const std::string& shader_source,
+                           std::string* info_log,
+                           std::string* translated_source,
+                           int* shader_version,
+                           AttributeMap* attrib_map,
+                           UniformMap* uniform_map,
+                           VaryingMap* varying_map,
+                           InterfaceBlockMap* interface_block_map,
+                           OutputVariableList* output_variable_list,
+                           NameMap* name_map));
   MOCK_CONST_METHOD0(
       GetStringForOptionsThatWouldAffectCompilation, std::string());
  private:
diff --git a/gpu/command_buffer/service/program_manager.cc b/gpu/command_buffer/service/program_manager.cc
index bfff34c..45b0c55 100644
--- a/gpu/command_buffer/service/program_manager.cc
+++ b/gpu/command_buffer/service/program_manager.cc
@@ -28,6 +28,7 @@
 #include "gpu/command_buffer/service/program_cache.h"
 #include "gpu/command_buffer/service/shader_manager.h"
 #include "third_party/re2/re2/re2.h"
+#include "ui/gl/gl_version_info.h"
 
 using base::TimeDelta;
 using base::TimeTicks;
@@ -249,10 +250,9 @@
 }
 Program::UniformInfo::~UniformInfo() {}
 
-bool ProgramManager::IsInvalidPrefix(const char* name, size_t length) {
-  static const char kInvalidPrefix[] = { 'g', 'l', '_' };
-  return (length >= sizeof(kInvalidPrefix) &&
-      memcmp(name, kInvalidPrefix, sizeof(kInvalidPrefix)) == 0);
+bool ProgramManager::HasBuiltInPrefix(const std::string& name) {
+  return name.length() >= 3 && name[0] == 'g' && name[1] == 'l' &&
+         name[2] == '_';
 }
 
 Program::Program(ProgramManager* manager, GLuint service_id)
@@ -279,6 +279,7 @@
   uniform_locations_.clear();
   fragment_input_infos_.clear();
   fragment_input_locations_.clear();
+  program_output_infos_.clear();
   sampler_indices_.clear();
   attrib_location_to_index_map_.clear();
 }
@@ -519,6 +520,7 @@
 #endif
 
   UpdateFragmentInputs();
+  UpdateProgramOutputs();
 
   valid_ = true;
 }
@@ -563,8 +565,7 @@
 
     GLint service_location = -1;
     // Force builtin uniforms (gl_DepthRange) to have invalid location.
-    if (!ProgramManager::IsInvalidPrefix(service_name.c_str(),
-                                         service_name.size())) {
+    if (!ProgramManager::HasBuiltInPrefix(service_name)) {
       service_location =
           glGetUniformLocation(service_id_, service_name.c_str());
     }
@@ -701,9 +702,9 @@
     // A fragment shader can have gl_FragCoord, gl_FrontFacing or gl_PointCoord
     // built-ins as its input, as well as custom varyings. We are interested in
     // custom varyings, client is allowed to bind only them.
-    if (ProgramManager::IsInvalidPrefix(name_buffer.get(), name_length))
-      continue;
     std::string service_name(name_buffer.get(), name_length);
+    if (ProgramManager::HasBuiltInPrefix(service_name))
+      continue;
     // Unlike when binding uniforms, we expect the driver to give correct
     // names: "name" for simple variable, "name[0]" for an array.
     GLsizei query_length = 0;
@@ -788,6 +789,55 @@
   }
 }
 
+void Program::UpdateProgramOutputs() {
+  if (!feature_info().gl_version_info().IsES3Capable() ||
+      feature_info().disable_shader_translator())
+    return;
+
+  Shader* fragment_shader =
+      attached_shaders_[ShaderTypeToIndex(GL_FRAGMENT_SHADER)].get();
+
+  for (auto const& output_var : fragment_shader->output_variable_list()) {
+    const std::string& service_name = output_var.mappedName;
+    // A fragment shader can have gl_FragColor, gl_SecondaryFragColor, etc
+    // built-ins as its output, as well as custom varyings. We are interested
+    // only in custom varyings, client is allowed to bind only them.
+    if (ProgramManager::HasBuiltInPrefix(service_name))
+      continue;
+
+    std::string client_name = output_var.name;
+    if (output_var.arraySize == 0) {
+      GLint color_name =
+          glGetFragDataLocation(service_id_, service_name.c_str());
+      if (color_name < 0)
+        continue;
+      GLint index = 0;
+      if (feature_info().feature_flags().ext_blend_func_extended)
+        index = glGetFragDataIndex(service_id_, service_name.c_str());
+      if (index < 0)
+        continue;
+      program_output_infos_.push_back(
+          ProgramOutputInfo(color_name, index, client_name));
+    } else {
+      for (size_t ii = 0; ii < output_var.arraySize; ++ii) {
+        std::string array_spec(std::string("[") + base::IntToString(ii) + "]");
+        std::string service_element_name(service_name + array_spec);
+        GLint color_name =
+            glGetFragDataLocation(service_id_, service_element_name.c_str());
+        if (color_name < 0)
+          continue;
+        GLint index = 0;
+        if (feature_info().feature_flags().ext_blend_func_extended)
+          index = glGetFragDataIndex(service_id_, service_element_name.c_str());
+        if (index < 0)
+          continue;
+        program_output_infos_.push_back(
+            ProgramOutputInfo(color_name, index, client_name + array_spec));
+      }
+    }
+  }
+}
+
 void Program::ExecuteBindAttribLocationCalls() {
   for (const auto& key_value : bind_attrib_location_map_) {
     const std::string* mapped_name = GetAttribMappedName(key_value.first);
@@ -827,6 +877,96 @@
   return true;
 }
 
+void Program::ExecuteProgramOutputBindCalls() {
+  if (feature_info().disable_shader_translator()) {
+    return;
+  }
+
+  Shader* fragment_shader =
+      attached_shaders_[ShaderTypeToIndex(GL_FRAGMENT_SHADER)].get();
+  DCHECK(fragment_shader && fragment_shader->valid());
+
+  if (fragment_shader->shader_version() != 100) {
+    // ES SL 1.00 does not have mechanism for introducing variables that could
+    // be bound. This means that ES SL 1.00 binding calls would be to
+    // non-existing variable names.  Binding calls are only executed with ES SL
+    // 3.00 and higher.
+    for (auto const& output_var : fragment_shader->output_variable_list()) {
+      size_t count = std::max(output_var.arraySize, 1u);
+      bool is_array = output_var.arraySize > 0;
+
+      for (size_t jj = 0; jj < count; ++jj) {
+        std::string name = output_var.name;
+        std::string array_spec;
+        if (is_array) {
+          array_spec = std::string("[") + base::IntToString(jj) + "]";
+          name += array_spec;
+        }
+        auto it = bind_program_output_location_index_map_.find(name);
+        if (it == bind_program_output_location_index_map_.end())
+          continue;
+
+        std::string mapped_name = output_var.mappedName;
+        if (is_array) {
+          mapped_name += array_spec;
+        }
+        const auto& binding = it->second;
+        if (binding.second == 0) {
+          // Handles the cases where client called glBindFragDataLocation as
+          // well as glBindFragDataLocationIndexed with index == 0.
+          glBindFragDataLocation(service_id_, binding.first,
+                                 mapped_name.c_str());
+        } else {
+          DCHECK(feature_info().feature_flags().ext_blend_func_extended);
+          glBindFragDataLocationIndexed(service_id_, binding.first,
+                                        binding.second, mapped_name.c_str());
+        }
+      }
+    }
+    return;
+  }
+
+  // Support for EXT_blend_func_extended when used with ES SL 1.00 client
+  // shader.
+
+  if (feature_info().gl_version_info().is_es ||
+      !feature_info().feature_flags().ext_blend_func_extended)
+    return;
+
+  // The underlying context does not support EXT_blend_func_extended
+  // natively, need to emulate it.
+
+  // ES SL 1.00 is the only language which contains GLSL built-ins
+  // that need to be bound to color indices. If clients use other
+  // languages, they also bind the output variables themselves.
+  // Map gl_SecondaryFragColorEXT / gl_SecondaryFragDataEXT of
+  // EXT_blend_func_extended to real color indexes.
+  for (auto const& output_var : fragment_shader->output_variable_list()) {
+    const std::string& name = output_var.mappedName;
+    if (name == "gl_FragColor") {
+      DCHECK_EQ(-1, output_var.location);
+      DCHECK_EQ(0u, output_var.arraySize);
+      // We leave these unbound by not giving a binding name. The driver will
+      // bind this.
+    } else if (name == "gl_FragData") {
+      DCHECK_EQ(-1, output_var.location);
+      DCHECK_NE(0u, output_var.arraySize);
+      // We leave these unbound by not giving a binding name. The driver will
+      // bind this.
+    } else if (name == "gl_SecondaryFragColorEXT") {
+      DCHECK_EQ(-1, output_var.location);
+      DCHECK_EQ(0u, output_var.arraySize);
+      glBindFragDataLocationIndexed(service_id_, 0, 1,
+                                    "angle_SecondaryFragColor");
+    } else if (name == "gl_SecondaryFragDataEXT") {
+      DCHECK_EQ(-1, output_var.location);
+      DCHECK_NE(0u, output_var.arraySize);
+      glBindFragDataLocationIndexed(service_id_, 0, 1,
+                                    "angle_SecondaryFragData");
+    }
+  }
+}
+
 bool Program::Link(ShaderManager* manager,
                    Program::VaryingsPackingOption varyings_packing_option,
                    const ShaderCacheCallback& shader_callback) {
@@ -905,6 +1045,10 @@
       set_log_info("glBindFragmentInputLocationCHROMIUM() conflicts");
       return false;
     }
+    if (DetectProgramOutputLocationBindingConflicts()) {
+      set_log_info("glBindFragDataLocation() conflicts");
+      return false;
+    }
     if (DetectBuiltInInvariantConflicts()) {
       set_log_info("Invariant settings for certain built-in varyings "
                    "have to match");
@@ -925,6 +1069,9 @@
     if (!ExecuteTransformFeedbackVaryingsCall()) {
       return false;
     }
+
+    ExecuteProgramOutputBindCalls();
+
     before_time = TimeTicks::Now();
     if (cache && gfx::g_driver_gl.ext.b_GL_ARB_get_program_binary) {
       glProgramParameteri(service_id(),
@@ -1148,6 +1295,20 @@
   bind_fragment_input_location_map_[name + "[0]"] = location;
 }
 
+void Program::SetProgramOutputLocationBinding(const std::string& name,
+                                              GLuint color_name) {
+  SetProgramOutputLocationIndexedBinding(name, color_name, 0);
+}
+
+void Program::SetProgramOutputLocationIndexedBinding(const std::string& name,
+                                                     GLuint color_name,
+                                                     GLuint index) {
+  bind_program_output_location_index_map_[name] =
+      std::make_pair(color_name, index);
+  bind_program_output_location_index_map_[name + "[0]"] =
+      std::make_pair(color_name, index);
+}
+
 void Program::GetVertexAttribData(
     const std::string& name, std::string* original_name, GLenum* type) const {
   DCHECK(original_name);
@@ -1541,6 +1702,42 @@
   return false;
 }
 
+bool Program::DetectProgramOutputLocationBindingConflicts() const {
+  if (feature_info().disable_shader_translator()) {
+    return false;
+  }
+
+  Shader* shader =
+      attached_shaders_[ShaderTypeToIndex(GL_FRAGMENT_SHADER)].get();
+  DCHECK(shader && shader->valid());
+
+  if (shader->shader_version() == 100)
+    return false;
+
+  std::set<LocationIndexMap::mapped_type> location_binding_used;
+  for (auto const& output_var : shader->output_variable_list()) {
+    if (!output_var.staticUse)
+      continue;
+
+    size_t count = std::max(output_var.arraySize, 1u);
+    bool is_array = output_var.arraySize > 0;
+
+    for (size_t jj = 0; jj < count; ++jj) {
+      std::string name = output_var.name;
+      if (is_array)
+        name += std::string("[") + base::IntToString(jj) + "]";
+
+      auto it = bind_program_output_location_index_map_.find(name);
+      if (it == bind_program_output_location_index_map_.end())
+        continue;
+      auto result = location_binding_used.insert(it->second);
+      if (!result.second)
+        return true;
+    }
+  }
+  return false;
+}
+
 bool Program::DetectBuiltInInvariantConflicts() const {
   DCHECK(attached_shaders_[0].get() &&
          attached_shaders_[0]->shader_type() == GL_VERTEX_SHADER &&
@@ -2019,6 +2216,36 @@
   return true;
 }
 
+const Program::ProgramOutputInfo* Program::GetProgramOutputInfo(
+    const std::string& name) const {
+  for (const auto& info : program_output_infos_) {
+    if (info.name == name) {
+      return &info;
+    }
+  }
+  return nullptr;
+}
+
+GLint Program::GetFragDataLocation(const std::string& original_name) const {
+  DCHECK(IsValid());
+  const ProgramOutputInfo* info = GetProgramOutputInfo(original_name);
+  if (!info)
+    info = GetProgramOutputInfo(original_name + "[0]");
+  if (!info)
+    return -1;
+  return info->color_name;
+}
+
+GLint Program::GetFragDataIndex(const std::string& original_name) const {
+  DCHECK(IsValid());
+  const ProgramOutputInfo* info = GetProgramOutputInfo(original_name);
+  if (!info)
+    info = GetProgramOutputInfo(original_name + "[0]");
+  if (!info)
+    return -1;
+  return info->index;
+}
+
 void Program::TransformFeedbackVaryings(GLsizei count,
                                         const char* const* varyings,
                                         GLenum buffer_mode) {
@@ -2041,11 +2268,13 @@
 
 ProgramManager::ProgramManager(ProgramCache* program_cache,
                                uint32 max_varying_vectors,
+                               uint32 max_dual_source_draw_buffers,
                                FeatureInfo* feature_info)
     : program_count_(0),
       have_context_(true),
       program_cache_(program_cache),
       max_varying_vectors_(max_varying_vectors),
+      max_dual_source_draw_buffers_(max_dual_source_draw_buffers),
       feature_info_(feature_info) {}
 
 ProgramManager::~ProgramManager() {
diff --git a/gpu/command_buffer/service/program_manager.h b/gpu/command_buffer/service/program_manager.h
index 942659d..eb3be7c3 100644
--- a/gpu/command_buffer/service/program_manager.h
+++ b/gpu/command_buffer/service/program_manager.h
@@ -20,6 +20,7 @@
 namespace gpu {
 namespace gles2 {
 
+class FeatureInfo;
 class ProgramCache;
 class ProgramManager;
 class Shader;
@@ -69,6 +70,16 @@
     GLenum type;
     GLuint location;
   };
+  struct ProgramOutputInfo {
+    ProgramOutputInfo(GLuint _color_name,
+                      GLuint _index,
+                      const std::string& _name)
+        : color_name(_color_name), index(_index), name(_name) {}
+    ProgramOutputInfo() : color_name(0), index(0) {}
+    GLuint color_name;
+    GLuint index;
+    std::string name;
+  };
 
   struct UniformInfo {
     UniformInfo();
@@ -144,8 +155,10 @@
   typedef std::vector<FragmentInputInfo> FragmentInputInfoVector;
   typedef std::vector<ShaderVariableLocationEntry<FragmentInputInfo>>
       FragmentInputLocationVector;
+  typedef std::vector<ProgramOutputInfo> ProgramOutputInfoVector;
   typedef std::vector<int> SamplerIndices;
   typedef std::map<std::string, GLint> LocationMap;
+  typedef std::map<std::string, std::pair<GLuint, GLuint>> LocationIndexMap;
   typedef std::vector<std::string> StringVector;
 
   Program(ProgramManager* manager, GLuint service_id);
@@ -209,6 +222,10 @@
   // -1 for bound, non-existing uniform.
   bool IsInactiveUniformLocationByFakeLocation(GLint fake_location) const;
 
+  // Gets the ProgramOutputInfo of a fragment output by name.
+  const ProgramOutputInfo* GetProgramOutputInfo(
+      const std::string& original_name) const;
+
   // Gets all the program info.
   void GetProgramInfo(
       ProgramManager* manager, CommonDecoder::Bucket* bucket) const;
@@ -226,6 +243,14 @@
   // glGetProgramInfoCHROMIUM.
   bool GetUniformsES3(CommonDecoder::Bucket* bucket) const;
 
+  // Returns the fragment shader output variable color name binding.
+  // Returns -1 if |original_name| is not an out variable or error.
+  GLint GetFragDataLocation(const std::string& original_name) const;
+
+  // Returns the fragment shader output variable color index binding.
+  // Returns -1 if |original_name| is not an out variable or error.
+  GLint GetFragDataIndex(const std::string& original_name) const;
+
   // Sets the sampler values for a uniform.
   // This is safe to call for any location. If the location is not
   // a sampler uniform nothing will happen.
@@ -285,6 +310,15 @@
   // glBindFragmentInputLocationCHROMIUM() call.
   void SetFragmentInputLocationBinding(const std::string& name, GLint location);
 
+  // Sets program output variable location. Also sets color index to zero.
+  void SetProgramOutputLocationBinding(const std::string& name,
+                                       GLuint colorName);
+
+  // Sets program output variable location and color index.
+  void SetProgramOutputLocationIndexedBinding(const std::string& name,
+                                              GLuint colorName,
+                                              GLuint index);
+
   // Detects if there are attribute location conflicts from
   // glBindAttribLocation() calls.
   // We only consider the declared attributes in the program.
@@ -310,6 +344,11 @@
   // We only consider the statically used fragment inputs in the program.
   bool DetectFragmentInputLocationBindingConflicts() const;
 
+  // Detects if there are program output location conflicts from
+  // glBindFragDataLocation and ..LocationIndexedEXT calls.
+  // We only consider the statically used program outputs in the program.
+  bool DetectProgramOutputLocationBindingConflicts() const;
+
   // Return true if any built-in invariant matching rules are broken as in
   // GLSL ES spec 1.00.17, section 4.6.4, Invariance and Linkage.
   bool DetectBuiltInInvariantConflicts() const;
@@ -372,6 +411,7 @@
   void Update();
   void UpdateUniforms();
   void UpdateFragmentInputs();
+  void UpdateProgramOutputs();
 
   // Process the program log, replacing the hashed names with original names.
   std::string ProcessLogInfo(const std::string& log);
@@ -405,6 +445,8 @@
   // Returns false upon failure.
   bool ExecuteTransformFeedbackVaryingsCall();
 
+  void ExecuteProgramOutputBindCalls();
+
   // Query VertexAttrib data returned by ANGLE translator by the mapped name.
   void GetVertexAttribData(
       const std::string& name, std::string* original_name, GLenum* type) const;
@@ -447,6 +489,8 @@
   FragmentInputInfoVector fragment_input_infos_;
   FragmentInputLocationVector fragment_input_locations_;
 
+  ProgramOutputInfoVector program_output_infos_;
+
   // The program this Program is tracking.
   GLuint service_id_;
 
@@ -482,6 +526,10 @@
   // Fragment input-location binding map from
   // glBindFragmentInputLocationCHROMIUM() calls.
   LocationMap bind_fragment_input_location_map_;
+
+  // output variable - (location,index) binding map from
+  // glBindFragDataLocation() and ..IndexedEXT() calls.
+  LocationIndexMap bind_program_output_location_index_map_;
 };
 
 // Tracks the Programs.
@@ -492,6 +540,7 @@
  public:
   explicit ProgramManager(ProgramCache* program_cache,
                           uint32 max_varying_vectors,
+                          uint32 max_dual_source_draw_buffers,
                           FeatureInfo* feature_info);
   ~ProgramManager();
 
@@ -522,8 +571,9 @@
   // Clears the uniforms for this program.
   void ClearUniforms(Program* program);
 
-  // Returns true if prefix is invalid for gl.
-  static bool IsInvalidPrefix(const char* name, size_t length);
+  // Returns true if |name| has a prefix that is intended for GL built-in shader
+  // variables.
+  static bool HasBuiltInPrefix(const std::string& name);
 
   // Check if a Program is owned by this ProgramManager.
   bool IsOwned(Program* program) const;
@@ -534,6 +584,10 @@
     return max_varying_vectors_;
   }
 
+  uint32 max_dual_source_draw_buffers() const {
+    return max_dual_source_draw_buffers_;
+  }
+
  private:
   friend class Program;
 
@@ -560,6 +614,7 @@
   ProgramCache* program_cache_;
 
   uint32 max_varying_vectors_;
+  uint32 max_dual_source_draw_buffers_;
 
   scoped_refptr<FeatureInfo> feature_info_;
 
diff --git a/gpu/command_buffer/service/program_manager_unittest.cc b/gpu/command_buffer/service/program_manager_unittest.cc
index 404017f..8343e56e 100644
--- a/gpu/command_buffer/service/program_manager_unittest.cc
+++ b/gpu/command_buffer/service/program_manager_unittest.cc
@@ -21,6 +21,7 @@
 #include "gpu/command_buffer/service/test_helper.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/gl/gl_mock.h"
+#include "ui/gl/gl_version_info.h"
 
 using ::testing::_;
 using ::testing::DoAll;
@@ -38,6 +39,8 @@
 
 namespace {
 const uint32 kMaxVaryingVectors = 8;
+const uint32 kMaxDrawBuffers = 8;
+const uint32 kMaxDualSourceDrawBuffers = 8;
 
 void ShaderCacheCb(const std::string& key, const std::string& shader) {}
 
@@ -51,8 +54,9 @@
 class ProgramManagerTestBase : public GpuServiceTest {
  protected:
   virtual void SetupProgramManager() {
-    manager_.reset(
-        new ProgramManager(NULL, kMaxVaryingVectors, feature_info_.get()));
+    manager_.reset(new ProgramManager(nullptr, kMaxVaryingVectors,
+                                      kMaxDualSourceDrawBuffers,
+                                      feature_info_.get()));
   }
   void SetUpBase(const char* gl_version,
                  const char* gl_extensions,
@@ -215,6 +219,13 @@
   static const GLint kInvalidUniformLocation = 30;
   static const GLint kBadUniformIndex = 1000;
 
+  static const char* kOutputVariable1Name;
+  static const GLint kOutputVariable1Size = 1;
+  static const GLenum kOutputVariable1Precision = GL_MEDIUM_FLOAT;
+  static const bool kOutputVariable1StaticUse = true;
+  static const GLint kOutputVariable1Location = -1;
+  static const GLenum kOutputVariable1Type = GL_FLOAT_VEC4;
+
   static const size_t kNumAttribs;
   static const size_t kNumUniforms;
 
@@ -225,7 +236,8 @@
   typedef enum {
     kVarUniform,
     kVarVarying,
-    kVarAttribute
+    kVarAttribute,
+    kVarOutput,
   } VarCategory;
 
   typedef struct {
@@ -299,14 +311,16 @@
     return (static_cast<bool>(link_status) == expected_link_status);
   }
 
-  Program* SetupShaderVariableTest(const VarInfo* vertex_variables,
-                                   size_t vertex_variable_size,
-                                   const VarInfo* fragment_variables,
-                                   size_t fragment_variable_size) {
+  Program* SetupProgramForVariables(const VarInfo* vertex_variables,
+                                    size_t vertex_variable_size,
+                                    const VarInfo* fragment_variables,
+                                    size_t fragment_variable_size,
+                                    const int* const shader_version = nullptr) {
     // Set up shader
     AttributeMap vertex_attrib_map;
     UniformMap vertex_uniform_map;
     VaryingMap vertex_varying_map;
+    OutputVariableList vertex_output_variable_list;
     for (size_t ii = 0; ii < vertex_variable_size; ++ii) {
       switch (vertex_variables[ii].category) {
         case kVarAttribute:
@@ -336,6 +350,13 @@
                   vertex_variables[ii].static_use,
                   vertex_variables[ii].name);
           break;
+        case kVarOutput:
+          vertex_output_variable_list.push_back(
+              TestHelper::ConstructOutputVariable(
+                  vertex_variables[ii].type, vertex_variables[ii].size,
+                  vertex_variables[ii].precision,
+                  vertex_variables[ii].static_use, vertex_variables[ii].name));
+          break;
         default:
           NOTREACHED();
       }
@@ -344,6 +365,7 @@
     AttributeMap frag_attrib_map;
     UniformMap frag_uniform_map;
     VaryingMap frag_varying_map;
+    OutputVariableList frag_output_variable_list;
     for (size_t ii = 0; ii < fragment_variable_size; ++ii) {
       switch (fragment_variables[ii].category) {
         case kVarAttribute:
@@ -373,6 +395,14 @@
                   fragment_variables[ii].static_use,
                   fragment_variables[ii].name);
           break;
+        case kVarOutput:
+          frag_output_variable_list.push_back(
+              TestHelper::ConstructOutputVariable(
+                  fragment_variables[ii].type, fragment_variables[ii].size,
+                  fragment_variables[ii].precision,
+                  fragment_variables[ii].static_use,
+                  fragment_variables[ii].name));
+          break;
         default:
           NOTREACHED();
       }
@@ -386,12 +416,14 @@
     // Check shader got created.
     EXPECT_TRUE(vshader != NULL && fshader != NULL);
     // Set Status
-    TestHelper::SetShaderStates(
-        gl_.get(), vshader, true, NULL, NULL, NULL, &vertex_attrib_map,
-        &vertex_uniform_map, &vertex_varying_map, NULL, NULL);
-    TestHelper::SetShaderStates(
-        gl_.get(), fshader, true, NULL, NULL, NULL,
-        &frag_attrib_map, &frag_uniform_map, &frag_varying_map, NULL, NULL);
+    TestHelper::SetShaderStates(gl_.get(), vshader, true, nullptr, nullptr,
+                                shader_version, &vertex_attrib_map,
+                                &vertex_uniform_map, &vertex_varying_map,
+                                nullptr, &vertex_output_variable_list, nullptr);
+    TestHelper::SetShaderStates(gl_.get(), fshader, true, nullptr, nullptr,
+                                shader_version, &frag_attrib_map,
+                                &frag_uniform_map, &frag_varying_map, nullptr,
+                                &frag_output_variable_list, nullptr);
 
     // Set up program
     Program* program =
@@ -502,6 +534,7 @@
 const char* ProgramManagerWithShaderTest::kUniform3Name = "uniform3";
 const char* ProgramManagerWithShaderTest::kUniform3NameWithArrayIndex =
     "uniform3[0]";
+const char* ProgramManagerWithShaderTest::kOutputVariable1Name = "outputVar1";
 
 TEST_F(ProgramManagerWithShaderTest, GetAttribInfos) {
   const Program* program = SetupDefaultProgram();
@@ -805,6 +838,7 @@
   AttributeMap attrib_map;
   UniformMap uniform_map;
   VaryingMap varying_map;
+  OutputVariableList output_variable_list;
   attrib_map[kAttrib1Name] = TestHelper::ConstructAttribute(
       kAttrib1Type, kAttrib1Size, kAttrib1Precision,
       kAttribStaticUse, kAttrib1Name);
@@ -823,18 +857,22 @@
   uniform_map[kUniform3Name] = TestHelper::ConstructUniform(
       kUniform3Type, kUniform3Size, kUniform3Precision,
       kUniform3StaticUse, kUniform3Name);
+  output_variable_list.push_back(TestHelper::ConstructOutputVariable(
+      kOutputVariable1Type, kOutputVariable1Size, kOutputVariable1Precision,
+      kOutputVariable1StaticUse, kOutputVariable1Name));
+
   Shader* vshader = shader_manager_.CreateShader(
       kVertexShaderClientId, kVertexShaderServiceId, GL_VERTEX_SHADER);
   ASSERT_TRUE(vshader != NULL);
-  TestHelper::SetShaderStates(
-      gl_.get(), vshader, true, NULL, NULL, NULL,
-      &attrib_map, &uniform_map, &varying_map, NULL, NULL);
+  TestHelper::SetShaderStates(gl_.get(), vshader, true, nullptr, nullptr,
+                              nullptr, &attrib_map, &uniform_map, &varying_map,
+                              nullptr, &output_variable_list, nullptr);
   Shader* fshader = shader_manager_.CreateShader(
       kFragmentShaderClientId, kFragmentShaderServiceId, GL_FRAGMENT_SHADER);
   ASSERT_TRUE(fshader != NULL);
-  TestHelper::SetShaderStates(
-      gl_.get(), fshader, true, NULL, NULL, NULL,
-      &attrib_map, &uniform_map, &varying_map, NULL, NULL);
+  TestHelper::SetShaderStates(gl_.get(), fshader, true, nullptr, nullptr,
+                              nullptr, &attrib_map, &uniform_map, &varying_map,
+                              nullptr, &output_variable_list, nullptr);
   static ProgramManagerWithShaderTest::AttribInfo kAttribs[] = {
     { kAttrib1Name, kAttrib1Size, kAttrib1Type, kAttrib1Location, },
     { kAttrib2Name, kAttrib2Size, kAttrib2BadType, kAttrib2Location, },
@@ -1497,9 +1535,9 @@
   // Check shader got created.
   ASSERT_TRUE(vshader != NULL && fshader != NULL);
   // Set Status
-  TestHelper::SetShaderStates(
-      gl_.get(), vshader, true, NULL, NULL, NULL, &attrib_map, NULL, NULL,
-      NULL, NULL);
+  TestHelper::SetShaderStates(gl_.get(), vshader, true, nullptr, nullptr,
+                              nullptr, &attrib_map, nullptr, nullptr, nullptr,
+                              nullptr, nullptr);
   // Check attrib infos got copied.
   for (AttributeMap::const_iterator it = attrib_map.begin();
        it != attrib_map.end(); ++it) {
@@ -1512,10 +1550,9 @@
     EXPECT_EQ(it->second.staticUse, variable_info->staticUse);
     EXPECT_EQ(it->second.name, variable_info->name);
   }
-  TestHelper::SetShaderStates(
-      gl_.get(), fshader, true, NULL, NULL, NULL, &attrib_map, NULL, NULL,
-      NULL, NULL);
-
+  TestHelper::SetShaderStates(gl_.get(), fshader, true, nullptr, nullptr,
+                              nullptr, &attrib_map, nullptr, nullptr, nullptr,
+                              nullptr, nullptr);
   // Set up program
   Program* program =
       manager_->CreateProgram(kClientProgramId, kServiceProgramId);
@@ -1581,13 +1618,12 @@
   // Check shader got created.
   ASSERT_TRUE(vshader != NULL && fshader != NULL);
   // Set Status
-  TestHelper::SetShaderStates(
-      gl_.get(), vshader, true, NULL, NULL, NULL, NULL,
-      &vertex_uniform_map, NULL, NULL, NULL);
-  TestHelper::SetShaderStates(
-      gl_.get(), fshader, true, NULL, NULL, NULL, NULL,
-      &frag_uniform_map, NULL, NULL, NULL);
-
+  TestHelper::SetShaderStates(gl_.get(), vshader, true, nullptr, nullptr,
+                              nullptr, nullptr, &vertex_uniform_map, nullptr,
+                              nullptr, nullptr, nullptr);
+  TestHelper::SetShaderStates(gl_.get(), fshader, true, nullptr, nullptr,
+                              nullptr, nullptr, &frag_uniform_map, nullptr,
+                              nullptr, nullptr, nullptr);
   // Set up program
   Program* program =
       manager_->CreateProgram(kClientProgramId, kServiceProgramId);
@@ -1609,8 +1645,8 @@
       { GL_FLOAT_VEC3, 1, GL_MEDIUM_FLOAT, true, "a", kVarVarying };
   const VarInfo kFragmentVarying =
       { GL_FLOAT_VEC4, 1, GL_MEDIUM_FLOAT, true, "a", kVarVarying };
-  Program* program = SetupShaderVariableTest(
-      &kVertexVarying, 1, &kFragmentVarying, 1);
+  Program* program =
+      SetupProgramForVariables(&kVertexVarying, 1, &kFragmentVarying, 1);
 
   std::string conflicting_name;
 
@@ -1626,8 +1662,8 @@
       { GL_FLOAT, 2, GL_MEDIUM_FLOAT, true, "a", kVarVarying };
   const VarInfo kFragmentVarying =
       { GL_FLOAT, 3, GL_MEDIUM_FLOAT, true, "a", kVarVarying };
-  Program* program = SetupShaderVariableTest(
-      &kVertexVarying, 1, &kFragmentVarying, 1);
+  Program* program =
+      SetupProgramForVariables(&kVertexVarying, 1, &kFragmentVarying, 1);
 
   std::string conflicting_name;
 
@@ -1643,8 +1679,8 @@
       { GL_FLOAT, 2, GL_HIGH_FLOAT, true, "a", kVarVarying };
   const VarInfo kFragmentVarying =
       { GL_FLOAT, 2, GL_MEDIUM_FLOAT, true, "a", kVarVarying };
-  Program* program = SetupShaderVariableTest(
-      &kVertexVarying, 1, &kFragmentVarying, 1);
+  Program* program =
+      SetupProgramForVariables(&kVertexVarying, 1, &kFragmentVarying, 1);
 
   std::string conflicting_name;
 
@@ -1658,8 +1694,7 @@
 TEST_F(ProgramManagerWithShaderTest, VaryingMissing) {
   const VarInfo kFragmentVarying =
       { GL_FLOAT, 3, GL_MEDIUM_FLOAT, true, "a", kVarVarying };
-  Program* program = SetupShaderVariableTest(
-      NULL, 0, &kFragmentVarying, 1);
+  Program* program = SetupProgramForVariables(nullptr, 0, &kFragmentVarying, 1);
 
   std::string conflicting_name;
 
@@ -1674,8 +1709,7 @@
 TEST_F(ProgramManagerWithShaderTest, InactiveVarying) {
   const VarInfo kFragmentVarying =
       { GL_FLOAT, 3, GL_MEDIUM_FLOAT, false, "a", kVarVarying };
-  Program* program = SetupShaderVariableTest(
-      NULL, 0, &kFragmentVarying, 1);
+  Program* program = SetupProgramForVariables(nullptr, 0, &kFragmentVarying, 1);
 
   std::string conflicting_name;
 
@@ -1692,8 +1726,8 @@
       { GL_FLOAT_VEC4, 1, GL_MEDIUM_FLOAT, true, "a", kVarAttribute };
   const VarInfo kFragmentUniform =
       { GL_FLOAT_VEC4, 1, GL_MEDIUM_FLOAT, true, "a", kVarUniform };
-  Program* program = SetupShaderVariableTest(
-      &kVertexAttribute, 1, &kFragmentUniform, 1);
+  Program* program =
+      SetupProgramForVariables(&kVertexAttribute, 1, &kFragmentUniform, 1);
 
   std::string conflicting_name;
 
@@ -1712,8 +1746,8 @@
       { GL_FLOAT_VEC4, 4, GL_MEDIUM_FLOAT, true, "a", kVarVarying },
       { GL_FLOAT_VEC4, 5, GL_MEDIUM_FLOAT, true, "b", kVarVarying }
   };
-  Program* program = SetupShaderVariableTest(
-      kVertexVaryings, 2, kFragmentVaryings, 2);
+  Program* program =
+      SetupProgramForVariables(kVertexVaryings, 2, kFragmentVaryings, 2);
 
   EXPECT_FALSE(
       program->CheckVaryingsPacking(Program::kCountOnlyStaticallyUsed));
@@ -1730,8 +1764,8 @@
       { GL_FLOAT_VEC4, 4, GL_MEDIUM_FLOAT, false, "a", kVarVarying },
       { GL_FLOAT_VEC4, 5, GL_MEDIUM_FLOAT, true, "b", kVarVarying }
   };
-  Program* program = SetupShaderVariableTest(
-      kVertexVaryings, 2, kFragmentVaryings, 2);
+  Program* program =
+      SetupProgramForVariables(kVertexVaryings, 2, kFragmentVaryings, 2);
 
   EXPECT_TRUE(
       program->CheckVaryingsPacking(Program::kCountOnlyStaticallyUsed));
@@ -1749,8 +1783,8 @@
       { GL_FLOAT_VEC4, 4, GL_MEDIUM_FLOAT, false, "a", kVarVarying },
       { GL_FLOAT_VEC4, 5, GL_MEDIUM_FLOAT, true, "b", kVarVarying }
   };
-  Program* program = SetupShaderVariableTest(
-      kVertexVaryings, 2, kFragmentVaryings, 2);
+  Program* program =
+      SetupProgramForVariables(kVertexVaryings, 2, kFragmentVaryings, 2);
 
   EXPECT_FALSE(program->CheckVaryingsPacking(Program::kCountAll));
 }
@@ -1910,6 +1944,7 @@
  protected:
   void SetupProgramManager() override {
     manager_.reset(new ProgramManager(cache_.get(), kMaxVaryingVectors,
+                                      kMaxDualSourceDrawBuffers,
                                       feature_info_.get()));
   }
 
@@ -1931,10 +1966,12 @@
     program_->AttachShader(&shader_manager_, vertex_shader_);
     program_->AttachShader(&shader_manager_, fragment_shader_);
   }
+
   void TearDown() override {
     shader_manager_.Destroy(false);
     ProgramManagerTestBase::TearDown();
   }
+
   void SetShadersCompiled() {
     TestHelper::SetShaderStates(gl_.get(), vertex_shader_, true);
     TestHelper::SetShaderStates(gl_.get(), fragment_shader_, true);
@@ -2019,9 +2056,9 @@
   }
 
   void SetExpectationsForProgramLoadSuccess(GLuint service_program_id) {
-    TestHelper::SetupProgramSuccessExpectations(gl_.get(), feature_info_.get(),
-                                                nullptr, 0, nullptr, 0, nullptr,
-                                                0, service_program_id);
+    TestHelper::SetupProgramSuccessExpectations(
+        gl_.get(), feature_info_.get(), nullptr, 0, nullptr, 0, nullptr, 0,
+        nullptr, 0, service_program_id);
   }
 
   void SetExpectationsForProgramLink() {
@@ -2177,7 +2214,6 @@
 const char* ProgramManagerWithPathRenderingTest::kFragmentInput2Name = "color2";
 const char* ProgramManagerWithPathRenderingTest::kFragmentInput2GLName =
     "color2[0]";
-
 const char* ProgramManagerWithPathRenderingTest::kFragmentInput3Name = "color3";
 const char* ProgramManagerWithPathRenderingTest::kFragmentInput3GLName =
     "color3[0]";
@@ -2205,10 +2241,10 @@
       kFragmentInput3StaticUse, kFragmentInput3Name);
   TestHelper::SetShaderStates(gl_.get(), vshader, true, nullptr, nullptr,
                               nullptr, nullptr, nullptr, &varying_map, nullptr,
-                              nullptr);
+                              nullptr, nullptr);
   TestHelper::SetShaderStates(gl_.get(), fshader, true, nullptr, nullptr,
                               nullptr, nullptr, nullptr, &varying_map, nullptr,
-                              nullptr);
+                              nullptr, nullptr);
   Program* program =
       manager_->CreateProgram(kClientProgramId, kServiceProgramId);
   ASSERT_TRUE(program != NULL);
@@ -2238,7 +2274,7 @@
   TestHelper::SetupShaderExpectationsWithVaryings(
       gl_.get(), feature_info_.get(), nullptr, 0, nullptr, 0,
       kFragmentInputExpectationInfos, arraysize(kFragmentInputExpectationInfos),
-      kServiceProgramId);
+      nullptr, 0, kServiceProgramId);
   program->Link(NULL, Program::kCountOnlyStaticallyUsed,
                 base::Bind(&ShaderCacheCb));
   const Program::FragmentInputInfo* info1 =
@@ -2273,5 +2309,90 @@
         make_gl_ext_tuple("4.5", "GL_NV_path_rendering"),
         make_gl_ext_tuple("opengl es 3.1", "GL_NV_path_rendering")));
 
+class ProgramManagerDualSourceBlendingTest
+    : public ProgramManagerWithShaderTest,
+      public testing::WithParamInterface<
+          testing::tuple<const char*, const char*>> {
+ public:
+  ProgramManagerDualSourceBlendingTest() {}
+
+ protected:
+  void SetUpWithFeatureInfo(FeatureInfo* feature_info) {
+    const char* gl_version = testing::get<0>(GetParam());
+    const char* gl_extensions = testing::get<1>(GetParam());
+    SetUpBase(gl_version, gl_extensions, feature_info);
+  }
+
+  void SetUp() override { SetUpWithFeatureInfo(nullptr); }
+};
+
+class ProgramManagerDualSourceBlendingES2Test
+    : public ProgramManagerDualSourceBlendingTest {};
+
+TEST_P(ProgramManagerDualSourceBlendingES2Test, UseSecondaryFragCoord) {
+  DCHECK(feature_info_->feature_flags().ext_blend_func_extended);
+
+  const VarInfo kFragmentVaryings[] = {
+      {GL_FLOAT_VEC4, 0, GL_MEDIUM_FLOAT, true, "gl_SecondaryFragColorEXT",
+       kVarOutput},
+      {GL_FLOAT_VEC4, 0, GL_MEDIUM_FLOAT, true, "gl_FragColor", kVarOutput},
+  };
+
+  int shader_version = 100;
+  Program* program =
+      SetupProgramForVariables(nullptr, 0, kFragmentVaryings,
+                               arraysize(kFragmentVaryings), &shader_version);
+
+  const gfx::GLVersionInfo& gl_version = feature_info_->gl_version_info();
+  if (!gl_version.is_es) {
+    // The call is expected only for OpenGL. OpenGL ES expects to
+    // output GLES SL 1.00, which does not bind.
+    EXPECT_CALL(*(gl_.get()),
+                BindFragDataLocationIndexed(kServiceProgramId, 0, 1,
+                                            StrEq("angle_SecondaryFragColor")))
+        .Times(1)
+        .RetiresOnSaturation();
+  }
+
+  EXPECT_TRUE(LinkAsExpected(program, true));
+}
+
+TEST_P(ProgramManagerDualSourceBlendingES2Test, UseSecondaryFragData) {
+  const VarInfo kFragmentVaryings[] = {
+      {GL_FLOAT_VEC4, kMaxDualSourceDrawBuffers, GL_MEDIUM_FLOAT, true,
+       "gl_SecondaryFragDataEXT", kVarOutput},
+      {GL_FLOAT_VEC4, kMaxDrawBuffers, GL_MEDIUM_FLOAT, true, "gl_FragData",
+       kVarOutput},
+  };
+
+  int shader_version = 100;
+  Program* program =
+      SetupProgramForVariables(nullptr, 0, kFragmentVaryings,
+                               arraysize(kFragmentVaryings), &shader_version);
+
+  const gfx::GLVersionInfo& gl_version = feature_info_->gl_version_info();
+  if (!gl_version.is_es) {
+    // The call is expected only for OpenGL. OpenGL ES expects to
+    // output GLES SL 1.00, which does not bind.
+    EXPECT_CALL(*(gl_.get()),
+                BindFragDataLocationIndexed(kServiceProgramId, 0, 1,
+                                            StrEq("angle_SecondaryFragData")))
+        .Times(1)
+        .RetiresOnSaturation();
+  }
+
+  EXPECT_TRUE(LinkAsExpected(program, true));
+}
+
+INSTANTIATE_TEST_CASE_P(
+    SupportedContexts,
+    ProgramManagerDualSourceBlendingES2Test,
+    testing::Values(
+        make_gl_ext_tuple("3.2",
+                          "GL_ARB_draw_buffers GL_ARB_blend_func_extended "
+                          "GL_ARB_program_interface_query"),
+        make_gl_ext_tuple("opengl es 3.1",
+                          "GL_EXT_draw_buffers GL_EXT_blend_func_extended")));
+
 }  // namespace gles2
 }  // namespace gpu
diff --git a/gpu/command_buffer/service/shader_manager.cc b/gpu/command_buffer/service/shader_manager.cc
index 342a476..22df5f7 100644
--- a/gpu/command_buffer/service/shader_manager.cc
+++ b/gpu/command_buffer/service/shader_manager.cc
@@ -69,15 +69,10 @@
   const char* source_for_driver = last_compiled_source_.c_str();
   ShaderTranslatorInterface* translator = translator_.get();
   if (translator) {
-    bool success = translator->Translate(last_compiled_source_,
-                                         &log_info_,
-                                         &translated_source_,
-                                         &shader_version_,
-                                         &attrib_map_,
-                                         &uniform_map_,
-                                         &varying_map_,
-                                         &interface_block_map_,
-                                         &name_map_);
+    bool success = translator->Translate(
+        last_compiled_source_, &log_info_, &translated_source_,
+        &shader_version_, &attrib_map_, &uniform_map_, &varying_map_,
+        &interface_block_map_, &output_variable_list_, &name_map_);
     if (!success) {
       return;
     }
@@ -215,6 +210,15 @@
   return NULL;
 }
 
+const std::string* Shader::GetOutputVariableMappedName(
+    const std::string& original_name) const {
+  for (const auto& value : output_variable_list_) {
+    if (value.name == original_name)
+      return &value.mappedName;
+  }
+  return nullptr;
+}
+
 const std::string* Shader::GetOriginalNameFromHashedName(
     const std::string& hashed_name) const {
   NameMap::const_iterator it = name_map_.find(hashed_name);
@@ -249,6 +253,18 @@
   return it != interface_block_map_.end() ? &it->second : NULL;
 }
 
+const sh::OutputVariable* Shader::GetOutputVariableInfo(
+    const std::string& name) const {
+  std::string mapped_name = GetTopVariableName(name);
+  // Number of output variables is expected to be so low that
+  // a linear search of a list should be faster than using a map.
+  for (const auto& value : output_variable_list_) {
+    if (value.mappedName == mapped_name)
+      return &value;
+  }
+  return nullptr;
+}
+
 ShaderManager::ShaderManager() {}
 
 ShaderManager::~ShaderManager() {
diff --git a/gpu/command_buffer/service/shader_manager.h b/gpu/command_buffer/service/shader_manager.h
index 3288bff..1869371 100644
--- a/gpu/command_buffer/service/shader_manager.h
+++ b/gpu/command_buffer/service/shader_manager.h
@@ -88,6 +88,8 @@
   const sh::Varying* GetVaryingInfo(const std::string& name) const;
   const sh::InterfaceBlock* GetInterfaceBlockInfo(
       const std::string& name) const;
+  const sh::OutputVariable* GetOutputVariableInfo(
+      const std::string& name) const;
 
   // If the original_name is not found, return NULL.
   const std::string* GetAttribMappedName(
@@ -105,6 +107,10 @@
   const std::string* GetInterfaceBlockMappedName(
       const std::string& original_name) const;
 
+  // If the original_name is not found, return NULL.
+  const std::string* GetOutputVariableMappedName(
+      const std::string& original_name) const;
+
   // If the hashed_name is not found, return NULL.
   const std::string* GetOriginalNameFromHashedName(
       const std::string& hashed_name) const;
@@ -144,6 +150,10 @@
     return varying_map_;
   }
 
+  const OutputVariableList& output_variable_list() const {
+    return output_variable_list_;
+  }
+
   // Used by program cache.
   const InterfaceBlockMap& interface_block_map() const {
     return interface_block_map_;
@@ -177,6 +187,12 @@
     uniform_map_[uniform.mappedName] = uniform;
   }
 
+  void set_output_variable_list(
+      const OutputVariableList& output_variable_list) {
+    // copied because cache might be cleared
+    output_variable_list_ = output_variable_list;
+  }
+
  private:
   friend class base::RefCounted<Shader>;
   friend class ShaderManager;
@@ -237,6 +253,7 @@
   UniformMap uniform_map_;
   VaryingMap varying_map_;
   InterfaceBlockMap interface_block_map_;
+  OutputVariableList output_variable_list_;
 
   // The name hashing info when the shader was last compiled.
   NameMap name_map_;
diff --git a/gpu/command_buffer/service/shader_manager_unittest.cc b/gpu/command_buffer/service/shader_manager_unittest.cc
index c125cfe6..93471ec10 100644
--- a/gpu/command_buffer/service/shader_manager_unittest.cc
+++ b/gpu/command_buffer/service/shader_manager_unittest.cc
@@ -126,6 +126,11 @@
   const GLenum kVarying1Precision = GL_HIGH_FLOAT;
   const bool kVarying1StaticUse = false;
   const char* kVarying1Name = "varying1";
+  const GLenum kOutputVariable1Type = GL_FLOAT_VEC4;
+  const GLint kOutputVariable1Size = 4;
+  const GLenum kOutputVariable1Precision = GL_MEDIUM_FLOAT;
+  const char* kOutputVariable1Name = "gl_FragColor";
+  const bool kOutputVariable1StaticUse = true;
 
   // Check we can create shader.
   Shader* shader1 = manager_.CreateShader(
@@ -187,10 +192,13 @@
   varying_map[kVarying1Name] = TestHelper::ConstructVarying(
       kVarying1Type, kVarying1Size, kVarying1Precision,
       kVarying1StaticUse, kVarying1Name);
-
+  OutputVariableList output_variable_list;
+  output_variable_list.push_back(TestHelper::ConstructOutputVariable(
+      kOutputVariable1Type, kOutputVariable1Size, kOutputVariable1Precision,
+      kOutputVariable1StaticUse, kOutputVariable1Name));
   TestHelper::SetShaderStates(
-      gl_.get(), shader1, true, &kLog, &kTranslatedSource, NULL,
-      &attrib_map, &uniform_map, &varying_map, NULL, NULL);
+      gl_.get(), shader1, true, &kLog, &kTranslatedSource, nullptr, &attrib_map,
+      &uniform_map, &varying_map, nullptr, &output_variable_list, nullptr);
   EXPECT_TRUE(shader1->valid());
   // When compilation succeeds, no log is recorded.
   EXPECT_STREQ("", shader1->log_info().c_str());
@@ -233,17 +241,33 @@
     EXPECT_EQ(it->second.staticUse, variable_info->staticUse);
     EXPECT_STREQ(it->second.name.c_str(), variable_info->name.c_str());
   }
+  // Check output variable infos got copied.
+  EXPECT_EQ(output_variable_list.size(),
+            shader1->output_variable_list().size());
+  for (auto it = output_variable_list.begin(); it != output_variable_list.end();
+       ++it) {
+    const sh::OutputVariable* variable_info =
+        shader1->GetOutputVariableInfo(it->mappedName);
+    ASSERT_TRUE(variable_info != nullptr);
+    EXPECT_EQ(it->type, variable_info->type);
+    EXPECT_EQ(it->arraySize, variable_info->arraySize);
+    EXPECT_EQ(it->precision, variable_info->precision);
+    EXPECT_EQ(it->staticUse, variable_info->staticUse);
+    EXPECT_STREQ(it->name.c_str(), variable_info->name.c_str());
+  }
 
   // Compile failure case.
-  TestHelper::SetShaderStates(
-      gl_.get(), shader1, false, &kLog, &kTranslatedSource, NULL,
-      &attrib_map, &uniform_map, &varying_map, NULL, NULL);
+  TestHelper::SetShaderStates(gl_.get(), shader1, false, &kLog,
+                              &kTranslatedSource, nullptr, &attrib_map,
+                              &uniform_map, &varying_map, nullptr,
+                              &output_variable_list, nullptr);
   EXPECT_FALSE(shader1->valid());
   EXPECT_STREQ(kLog.c_str(), shader1->log_info().c_str());
   EXPECT_STREQ("", shader1->translated_source().c_str());
   EXPECT_TRUE(shader1->attrib_map().empty());
   EXPECT_TRUE(shader1->uniform_map().empty());
   EXPECT_TRUE(shader1->varying_map().empty());
+  EXPECT_TRUE(shader1->output_variable_list().empty());
 }
 
 TEST_F(ShaderManagerTest, ShaderInfoUseCount) {
diff --git a/gpu/command_buffer/service/shader_translator.cc b/gpu/command_buffer/service/shader_translator.cc
index 92c7f9d..255caff 100644
--- a/gpu/command_buffer/service/shader_translator.cc
+++ b/gpu/command_buffer/service/shader_translator.cc
@@ -71,6 +71,11 @@
       (*var_map)[(*varyings)[ii].mappedName] = (*varyings)[ii];
   }
 }
+void GetOutputVariables(ShHandle compiler, OutputVariableList* var_list) {
+  if (!var_list)
+    return;
+  *var_list = *ShGetOutputVariables(compiler);
+}
 
 void GetInterfaceBlocks(ShHandle compiler, InterfaceBlockMap* var_map) {
   if (!var_map)
@@ -206,6 +211,7 @@
                                  UniformMap* uniform_map,
                                  VaryingMap* varying_map,
                                  InterfaceBlockMap* interface_block_map,
+                                 OutputVariableList* output_variable_list,
                                  NameMap* name_map) const {
   // Make sure this instance is initialized.
   DCHECK(compiler_ != NULL);
@@ -224,11 +230,12 @@
     }
     // Get shader version.
     *shader_version = ShGetShaderVersion(compiler_);
-    // Get info for attribs, uniforms, and varyings.
+    // Get info for attribs, uniforms, varyings and output variables.
     GetAttributes(compiler_, attrib_map);
     GetUniforms(compiler_, uniform_map);
     GetVaryings(compiler_, varying_map);
     GetInterfaceBlocks(compiler_, interface_block_map);
+    GetOutputVariables(compiler_, output_variable_list);
     // Get info for name hashing.
     GetNameHashingInfo(compiler_, name_map);
   }
diff --git a/gpu/command_buffer/service/shader_translator.h b/gpu/command_buffer/service/shader_translator.h
index 58ba69f..5a4914d9 100644
--- a/gpu/command_buffer/service/shader_translator.h
+++ b/gpu/command_buffer/service/shader_translator.h
@@ -24,6 +24,7 @@
 
 // Mapping between variable name and info.
 typedef base::hash_map<std::string, sh::Attribute> AttributeMap;
+typedef std::vector<sh::OutputVariable> OutputVariableList;
 typedef base::hash_map<std::string, sh::Uniform> UniformMap;
 typedef base::hash_map<std::string, sh::Varying> VaryingMap;
 typedef base::hash_map<std::string, sh::InterfaceBlock> InterfaceBlockMap;
@@ -58,6 +59,7 @@
                          UniformMap* uniform_map,
                          VaryingMap* varying_map,
                          InterfaceBlockMap* interface_block_map,
+                         OutputVariableList* output_variable_list,
                          NameMap* name_map) const = 0;
 
   // Return a string that is unique for a specfic set of options that would
@@ -109,6 +111,7 @@
                  UniformMap* uniform_map,
                  VaryingMap* varying_map,
                  InterfaceBlockMap* interface_block_map,
+                 OutputVariableList* output_variable_list,
                  NameMap* name_map) const override;
 
   std::string GetStringForOptionsThatWouldAffectCompilation() const override;
diff --git a/gpu/command_buffer/service/shader_translator_unittest.cc b/gpu/command_buffer/service/shader_translator_unittest.cc
index eff11c1ca..e5b3f6b 100644
--- a/gpu/command_buffer/service/shader_translator_unittest.cc
+++ b/gpu/command_buffer/service/shader_translator_unittest.cc
@@ -98,16 +98,13 @@
   UniformMap uniform_map;
   VaryingMap varying_map;
   InterfaceBlockMap interface_block_map;
+  OutputVariableList output_variable_list;
   NameMap name_map;
-  EXPECT_TRUE(vertex_translator_->Translate(shader,
-                                            &info_log,
-                                            &translated_source,
-                                            &shader_version,
-                                            &attrib_map,
-                                            &uniform_map,
-                                            &varying_map,
-                                            &interface_block_map,
-                                            &name_map));
+  EXPECT_TRUE(vertex_translator_->Translate(
+      shader, &info_log, &translated_source, &shader_version, &attrib_map,
+      &uniform_map, &varying_map, &interface_block_map, &output_variable_list,
+      &name_map));
+
   // Info log must be NULL.
   EXPECT_TRUE(info_log.empty());
   // Translated shader must be valid and non-empty.
@@ -118,6 +115,7 @@
   EXPECT_TRUE(uniform_map.empty());
   EXPECT_TRUE(interface_block_map.empty());
   EXPECT_EQ(1u, varying_map.size());
+  EXPECT_TRUE(output_variable_list.empty());
   // There should be no name mapping.
   EXPECT_TRUE(name_map.empty());
 }
@@ -136,16 +134,12 @@
   UniformMap uniform_map;
   VaryingMap varying_map;
   InterfaceBlockMap interface_block_map;
+  OutputVariableList output_variable_list;
   NameMap name_map;
-  EXPECT_FALSE(vertex_translator_->Translate(bad_shader,
-                                             &info_log,
-                                             &translated_source,
-                                             &shader_version,
-                                             &attrib_map,
-                                             &uniform_map,
-                                             &varying_map,
-                                             &interface_block_map,
-                                             &name_map));
+  EXPECT_FALSE(vertex_translator_->Translate(
+      bad_shader, &info_log, &translated_source, &shader_version, &attrib_map,
+      &uniform_map, &varying_map, &interface_block_map, &output_variable_list,
+      &name_map));
   // Info log must be valid and non-empty.
   ASSERT_FALSE(info_log.empty());
   // Translated shader must be NULL.
@@ -156,19 +150,15 @@
   EXPECT_TRUE(uniform_map.empty());
   EXPECT_TRUE(varying_map.empty());
   EXPECT_TRUE(interface_block_map.empty());
+  EXPECT_TRUE(output_variable_list.empty());
   EXPECT_TRUE(name_map.empty());
 
   // Try a good shader after bad.
   info_log.clear();
-  EXPECT_TRUE(vertex_translator_->Translate(good_shader,
-                                            &info_log,
-                                            &translated_source,
-                                            &shader_version,
-                                            &attrib_map,
-                                            &uniform_map,
-                                            &varying_map,
-                                            &interface_block_map,
-                                            &name_map));
+  EXPECT_TRUE(vertex_translator_->Translate(
+      good_shader, &info_log, &translated_source, &shader_version, &attrib_map,
+      &uniform_map, &varying_map, &interface_block_map, &output_variable_list,
+      &name_map));
   EXPECT_TRUE(info_log.empty());
   EXPECT_FALSE(translated_source.empty());
   EXPECT_TRUE(interface_block_map.empty());
@@ -187,16 +177,12 @@
   UniformMap uniform_map;
   VaryingMap varying_map;
   InterfaceBlockMap interface_block_map;
+  OutputVariableList output_variable_list;
   NameMap name_map;
-  EXPECT_TRUE(fragment_translator_->Translate(shader,
-                                              &info_log,
-                                              &translated_source,
-                                              &shader_version,
-                                              &attrib_map,
-                                              &uniform_map,
-                                              &varying_map,
-                                              &interface_block_map,
-                                              &name_map));
+  EXPECT_TRUE(fragment_translator_->Translate(
+      shader, &info_log, &translated_source, &shader_version, &attrib_map,
+      &uniform_map, &varying_map, &interface_block_map, &output_variable_list,
+      &name_map));
   // Info log must be NULL.
   EXPECT_TRUE(info_log.empty());
   // Translated shader must be valid and non-empty.
@@ -208,6 +194,8 @@
   EXPECT_TRUE(varying_map.empty());
   EXPECT_TRUE(interface_block_map.empty());
   EXPECT_TRUE(name_map.empty());
+  // gl_FragColor.
+  EXPECT_EQ(1u, output_variable_list.size());
 }
 
 TEST_F(ShaderTranslatorTest, InvalidFragmentShader) {
@@ -219,17 +207,13 @@
   UniformMap uniform_map;
   VaryingMap varying_map;
   InterfaceBlockMap interface_block_map;
+  OutputVariableList output_variable_list;
   NameMap name_map;
   // An invalid shader should fail.
-  EXPECT_FALSE(fragment_translator_->Translate(shader,
-                                               &info_log,
-                                               &translated_source,
-                                               &shader_version,
-                                               &attrib_map,
-                                               &uniform_map,
-                                               &varying_map,
-                                               &interface_block_map,
-                                               &name_map));
+  EXPECT_FALSE(fragment_translator_->Translate(
+      shader, &info_log, &translated_source, &shader_version, &attrib_map,
+      &uniform_map, &varying_map, &interface_block_map, &output_variable_list,
+      &name_map));
   // Info log must be valid and non-empty.
   EXPECT_FALSE(info_log.empty());
   // Translated shader must be NULL.
@@ -239,6 +223,7 @@
   EXPECT_TRUE(attrib_map.empty());
   EXPECT_TRUE(uniform_map.empty());
   EXPECT_TRUE(varying_map.empty());
+  EXPECT_TRUE(output_variable_list.empty());
   EXPECT_TRUE(name_map.empty());
 }
 
@@ -255,16 +240,12 @@
   UniformMap uniform_map;
   VaryingMap varying_map;
   InterfaceBlockMap interface_block_map;
+  OutputVariableList output_variable_list;
   NameMap name_map;
-  EXPECT_TRUE(vertex_translator_->Translate(shader,
-                                            &info_log,
-                                            &translated_source,
-                                            &shader_version,
-                                            &attrib_map,
-                                            &uniform_map,
-                                            &varying_map,
-                                            &interface_block_map,
-                                            &name_map));
+  EXPECT_TRUE(vertex_translator_->Translate(
+      shader, &info_log, &translated_source, &shader_version, &attrib_map,
+      &uniform_map, &varying_map, &interface_block_map, &output_variable_list,
+      &name_map));
   // Info log must be NULL.
   EXPECT_TRUE(info_log.empty());
   // Translated shader must be valid and non-empty.
@@ -303,16 +284,12 @@
   UniformMap uniform_map;
   VaryingMap varying_map;
   InterfaceBlockMap interface_block_map;
+  OutputVariableList output_variable_list;
   NameMap name_map;
-  EXPECT_TRUE(fragment_translator_->Translate(shader,
-                                              &info_log,
-                                              &translated_source,
-                                              &shader_version,
-                                              &attrib_map,
-                                              &uniform_map,
-                                              &varying_map,
-                                              &interface_block_map,
-                                              &name_map));
+  EXPECT_TRUE(fragment_translator_->Translate(
+      shader, &info_log, &translated_source, &shader_version, &attrib_map,
+      &uniform_map, &varying_map, &interface_block_map, &output_variable_list,
+      &name_map));
   // Info log must be NULL.
   EXPECT_TRUE(info_log.empty());
   // Translated shader must be valid and non-empty.
@@ -344,6 +321,9 @@
   EXPECT_EQ(1u, info->arraySize);
   EXPECT_STREQ("color", info->name.c_str());
   EXPECT_STREQ("bar[1].foo.color[0]", original_name.c_str());
+  EXPECT_EQ(1u, output_variable_list.size());
+  ASSERT_TRUE(output_variable_list.size() > 0);
+  EXPECT_EQ(output_variable_list[0].mappedName, "gl_FragColor");
 }
 
 
@@ -372,16 +352,12 @@
   UniformMap uniform_map;
   VaryingMap varying_map;
   InterfaceBlockMap interface_block_map;
+  OutputVariableList output_variable_list;
   NameMap name_map;
-  EXPECT_FALSE(fragment_translator_->Translate(shader,
-                                               &info_log,
-                                               &translated_source,
-                                               &shader_version,
-                                               &attrib_map,
-                                               &uniform_map,
-                                               &varying_map,
-                                               &interface_block_map,
-                                               &name_map));
+  EXPECT_FALSE(fragment_translator_->Translate(
+      shader, &info_log, &translated_source, &shader_version, &attrib_map,
+      &uniform_map, &varying_map, &interface_block_map, &output_variable_list,
+      &name_map));
   // Info log must be valid and non-empty.
   ASSERT_FALSE(info_log.empty());
   // Translated shader must be NULL.
@@ -415,16 +391,12 @@
   UniformMap uniform_map;
   VaryingMap varying_map;
   InterfaceBlockMap interface_block_map;
+  OutputVariableList output_variable_list;
   NameMap name_map;
-  EXPECT_TRUE(fragment_translator_->Translate(shader,
-                                              &info_log,
-                                              &translated_source,
-                                              &shader_version,
-                                              &attrib_map,
-                                              &uniform_map,
-                                              &varying_map,
-                                              &interface_block_map,
-                                              &name_map));
+  EXPECT_TRUE(fragment_translator_->Translate(
+      shader, &info_log, &translated_source, &shader_version, &attrib_map,
+      &uniform_map, &varying_map, &interface_block_map, &output_variable_list,
+      &name_map));
   // Info log must be NULL.
   EXPECT_TRUE(info_log.empty());
   // Translated shader must be valid and non-empty.
@@ -509,7 +481,7 @@
   int shader_version;
   EXPECT_TRUE(translator->Translate(kShader, nullptr, &translated_source,
                                     &shader_version, nullptr, nullptr, nullptr,
-                                    nullptr, nullptr));
+                                    nullptr, nullptr, nullptr));
 
   std::string expected_version_directive = testing::get<1>(GetParam());
   if (expected_version_directive.empty()) {
diff --git a/gpu/command_buffer/service/test_helper.cc b/gpu/command_buffer/service/test_helper.cc
index 2c8fc25..40c285a 100644
--- a/gpu/command_buffer/service/test_helper.cc
+++ b/gpu/command_buffer/service/test_helper.cc
@@ -339,6 +339,16 @@
         .WillOnce(SetArgumentPointee<1>(kMaxSamples))
         .RetiresOnSaturation();
   }
+
+  if (gl_info.IsAtLeastGL(3, 3) ||
+      (gl_info.IsAtLeastGL(3, 2) &&
+       strstr(extensions, "GL_ARB_blend_func_extended")) ||
+      (gl_info.is_es && strstr(extensions, "GL_EXT_blend_func_extended"))) {
+    EXPECT_CALL(*gl, GetIntegerv(GL_MAX_DUAL_SOURCE_DRAW_BUFFERS_EXT, _))
+        .WillOnce(SetArgumentPointee<1>(8))
+        .RetiresOnSaturation();
+  }
+
   EXPECT_CALL(*gl, GetIntegerv(GL_MAX_VERTEX_ATTRIBS, _))
       .WillOnce(SetArgumentPointee<1>(kNumVertexAttribs))
       .RetiresOnSaturation();
@@ -689,6 +699,8 @@
     size_t num_uniforms,
     VaryingInfo* varyings,
     size_t num_varyings,
+    ProgramOutputInfo* program_outputs,
+    size_t num_program_outputs,
     GLuint service_id) {
   EXPECT_CALL(*gl,
       GetProgramiv(service_id, GL_LINK_STATUS, _))
@@ -724,7 +736,7 @@
             SetArrayArgument<6>(info.name,
                                 info.name + strlen(info.name) + 1)))
         .RetiresOnSaturation();
-    if (!ProgramManager::IsInvalidPrefix(info.name, strlen(info.name))) {
+    if (!ProgramManager::HasBuiltInPrefix(info.name)) {
       EXPECT_CALL(*gl, GetAttribLocation(service_id, StrEq(info.name)))
           .WillOnce(Return(info.location))
           .RetiresOnSaturation();
@@ -799,7 +811,9 @@
                           SetArrayArgument<5>(
                               info.name, info.name + strlen(info.name) + 1)))
           .RetiresOnSaturation();
-      if (!ProgramManager::IsInvalidPrefix(info.name, strlen(info.name))) {
+      if (ProgramManager::HasBuiltInPrefix(info.name))
+        continue;
+
         static const GLenum kPropsArray[] = {GL_LOCATION, GL_TYPE,
                                              GL_ARRAY_SIZE};
         static const size_t kPropsSize = arraysize(kPropsArray);
@@ -818,6 +832,26 @@
             }))
             .RetiresOnSaturation();
       }
+  }
+  if (feature_info->gl_version_info().IsES3Capable() &&
+      !feature_info->disable_shader_translator()) {
+    for (size_t ii = 0; ii < num_program_outputs; ++ii) {
+      ProgramOutputInfo& info = program_outputs[ii];
+      if (ProgramManager::HasBuiltInPrefix(info.name))
+        continue;
+
+      EXPECT_CALL(*gl, GetFragDataLocation(service_id, StrEq(info.name)))
+          .WillOnce(Return(info.color_name))
+          .RetiresOnSaturation();
+      if (feature_info->feature_flags().ext_blend_func_extended) {
+        EXPECT_CALL(*gl, GetFragDataIndex(service_id, StrEq(info.name)))
+            .WillOnce(Return(info.index))
+            .RetiresOnSaturation();
+      } else {
+        // Test case must not use indices, or the context of the testcase has to
+        // support the dual source blending.
+        DCHECK(info.index == 0);
+      }
     }
   }
 }
@@ -834,8 +868,8 @@
   EXPECT_CALL(*gl, LinkProgram(service_id)).Times(1).RetiresOnSaturation();
 
   SetupProgramSuccessExpectations(gl, feature_info, attribs, num_attribs,
-                                  uniforms, num_uniforms, nullptr, 0,
-                                  service_id);
+                                  uniforms, num_uniforms, nullptr, 0, nullptr,
+                                  0, service_id);
 }
 
 void TestHelper::SetupShaderExpectationsWithVaryings(
@@ -847,6 +881,8 @@
     size_t num_uniforms,
     VaryingInfo* varyings,
     size_t num_varyings,
+    ProgramOutputInfo* program_outputs,
+    size_t num_program_outputs,
     GLuint service_id) {
   InSequence s;
 
@@ -855,9 +891,9 @@
       .Times(1)
       .RetiresOnSaturation();
 
-  SetupProgramSuccessExpectations(gl, feature_info, attribs, num_attribs,
-                                  uniforms, num_uniforms, varyings,
-                                  num_varyings, service_id);
+  SetupProgramSuccessExpectations(
+      gl, feature_info, attribs, num_attribs, uniforms, num_uniforms, varyings,
+      num_varyings, program_outputs, num_program_outputs, service_id);
 }
 
 void TestHelper::DoBufferData(
@@ -905,16 +941,18 @@
 
 // static
 void TestHelper::SetShaderStates(
-      ::gfx::MockGLInterface* gl, Shader* shader,
-      bool expected_valid,
-      const std::string* const expected_log_info,
-      const std::string* const expected_translated_source,
-      const int* const expected_shader_version,
-      const AttributeMap* const expected_attrib_map,
-      const UniformMap* const expected_uniform_map,
-      const VaryingMap* const expected_varying_map,
-      const InterfaceBlockMap* const expected_interface_block_map,
-      const NameMap* const expected_name_map) {
+    ::gfx::MockGLInterface* gl,
+    Shader* shader,
+    bool expected_valid,
+    const std::string* const expected_log_info,
+    const std::string* const expected_translated_source,
+    const int* const expected_shader_version,
+    const AttributeMap* const expected_attrib_map,
+    const UniformMap* const expected_uniform_map,
+    const VaryingMap* const expected_varying_map,
+    const InterfaceBlockMap* const expected_interface_block_map,
+    const OutputVariableList* const expected_output_variable_list,
+    const NameMap* const expected_name_map) {
   const std::string empty_log_info;
   const std::string* log_info = (expected_log_info && !expected_valid) ?
       expected_log_info : &empty_log_info;
@@ -938,6 +976,11 @@
   const InterfaceBlockMap* interface_block_map =
       (expected_interface_block_map && expected_valid) ?
       expected_interface_block_map : &empty_interface_block_map;
+  const OutputVariableList empty_output_variable_list;
+  const OutputVariableList* output_variable_list =
+      (expected_output_variable_list && expected_valid)
+          ? expected_output_variable_list
+          : &empty_output_variable_list;
   const NameMap empty_name_map;
   const NameMap* name_map = (expected_name_map && expected_valid) ?
       expected_name_map : &empty_name_map;
@@ -945,13 +988,14 @@
   MockShaderTranslator* mock_translator = new MockShaderTranslator;
   scoped_refptr<ShaderTranslatorInterface> translator(mock_translator);
   EXPECT_CALL(*mock_translator, Translate(_,
-                                          NotNull(),  // log_info
-                                          NotNull(),  // translated_source
-                                          NotNull(),  // shader_version
-                                          NotNull(),  // attrib_map
-                                          NotNull(),  // uniform_map
-                                          NotNull(),  // varying_map
-                                          NotNull(),  // interface_block_map
+                                          NotNull(),   // log_info
+                                          NotNull(),   // translated_source
+                                          NotNull(),   // shader_version
+                                          NotNull(),   // attrib_map
+                                          NotNull(),   // uniform_map
+                                          NotNull(),   // varying_map
+                                          NotNull(),   // interface_block_map
+                                          NotNull(),   // output_variable_list
                                           NotNull()))  // name_map
       .WillOnce(DoAll(SetArgumentPointee<1>(*log_info),
                       SetArgumentPointee<2>(*translated_source),
@@ -960,8 +1004,8 @@
                       SetArgumentPointee<5>(*uniform_map),
                       SetArgumentPointee<6>(*varying_map),
                       SetArgumentPointee<7>(*interface_block_map),
-                      SetArgumentPointee<8>(*name_map),
-                      Return(expected_valid)))
+                      SetArgumentPointee<8>(*output_variable_list),
+                      SetArgumentPointee<9>(*name_map), Return(expected_valid)))
       .RetiresOnSaturation();
   if (expected_valid) {
     EXPECT_CALL(*gl, ShaderSource(shader->service_id(), 1, _, NULL))
@@ -983,8 +1027,8 @@
 // static
 void TestHelper::SetShaderStates(
       ::gfx::MockGLInterface* gl, Shader* shader, bool valid) {
-  SetShaderStates(
-      gl, shader, valid, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+  SetShaderStates(gl, shader, valid, nullptr, nullptr, nullptr, nullptr,
+                  nullptr, nullptr, nullptr, nullptr, nullptr);
 }
 
 // static
@@ -1011,6 +1055,16 @@
       type, array_size, precision, static_use, name);
 }
 
+sh::OutputVariable TestHelper::ConstructOutputVariable(
+    GLenum type,
+    GLint array_size,
+    GLenum precision,
+    bool static_use,
+    const std::string& name) {
+  return ConstructShaderVariable<sh::OutputVariable>(
+      type, array_size, precision, static_use, name);
+}
+
 ScopedGLImplementationSetter::ScopedGLImplementationSetter(
     gfx::GLImplementation implementation)
     : old_implementation_(gfx::GetGLImplementation()) {
diff --git a/gpu/command_buffer/service/test_helper.h b/gpu/command_buffer/service/test_helper.h
index 33c91fb..7072428e 100644
--- a/gpu/command_buffer/service/test_helper.h
+++ b/gpu/command_buffer/service/test_helper.h
@@ -82,6 +82,13 @@
     GLint real_location;
     GLint desired_location;
   };
+  struct ProgramOutputInfo {
+    const char* name;
+    GLint size;
+    GLenum type;
+    GLint color_name;
+    GLuint index;
+  };
 
   static void SetupContextGroupInitExpectations(
       ::gfx::MockGLInterface* gl,
@@ -126,17 +133,22 @@
       size_t num_uniforms,
       VaryingInfo* varyings,
       size_t num_varyings,
+      ProgramOutputInfo* program_outputs,
+      size_t num_program_outputs,
       GLuint service_id);
 
-  static void SetupProgramSuccessExpectations(::gfx::MockGLInterface* gl,
-                                              const FeatureInfo* feature_info,
-                                              AttribInfo* attribs,
-                                              size_t num_attribs,
-                                              UniformInfo* uniforms,
-                                              size_t num_uniforms,
-                                              VaryingInfo* varyings,
-                                              size_t num_varyings,
-                                              GLuint service_id);
+  static void SetupProgramSuccessExpectations(
+      ::gfx::MockGLInterface* gl,
+      const FeatureInfo* feature_info,
+      AttribInfo* attribs,
+      size_t num_attribs,
+      UniformInfo* uniforms,
+      size_t num_uniforms,
+      VaryingInfo* varyings,
+      size_t num_varyings,
+      ProgramOutputInfo* program_outputs,
+      size_t num_program_outputs,
+      GLuint service_id);
 
   static void DoBufferData(
       ::gfx::MockGLInterface* gl, MockErrorState* error_state,
@@ -149,7 +161,8 @@
       GLenum pname, GLint value, GLenum error);
 
   static void SetShaderStates(
-      ::gfx::MockGLInterface* gl, Shader* shader,
+      ::gfx::MockGLInterface* gl,
+      Shader* shader,
       bool expected_valid,
       const std::string* const expected_log_info,
       const std::string* const expected_translated_source,
@@ -158,6 +171,7 @@
       const UniformMap* const expected_uniform_map,
       const VaryingMap* const expected_varying_map,
       const InterfaceBlockMap* const expected_interface_block_map,
+      const OutputVariableList* const expected_output_variable_list,
       const NameMap* const expected_name_map);
 
   static void SetShaderStates(
@@ -172,6 +186,11 @@
   static sh::Varying ConstructVarying(
       GLenum type, GLint array_size, GLenum precision,
       bool static_use, const std::string& name);
+  static sh::OutputVariable ConstructOutputVariable(GLenum type,
+                                                    GLint array_size,
+                                                    GLenum precision,
+                                                    bool static_use,
+                                                    const std::string& name);
 
  private:
   static void SetupTextureInitializationExpectations(::gfx::MockGLInterface* gl,
diff --git a/gpu/command_buffer/tests/gl_ext_blend_func_extended_unittest.cc b/gpu/command_buffer/tests/gl_ext_blend_func_extended_unittest.cc
new file mode 100644
index 0000000..d2f01ab
--- /dev/null
+++ b/gpu/command_buffer/tests/gl_ext_blend_func_extended_unittest.cc
@@ -0,0 +1,653 @@
+// Copyright (c) 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.
+
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#include <GLES2/gl2extchromium.h>
+#include <GLES3/gl3.h>
+
+#include "base/command_line.h"
+#include "base/strings/string_number_conversions.h"
+#include "gpu/command_buffer/service/gpu_switches.h"
+#include "gpu/command_buffer/tests/gl_manager.h"
+#include "gpu/command_buffer/tests/gl_test_utils.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gl/gl_switches.h"
+
+#define SHADER(Src) #Src
+#define BFE_SHADER(Src) "#extension GL_EXT_blend_func_extended : require\n" #Src
+
+namespace {
+// Partial implementation of weight function for GLES 2 blend equation that
+// is dual-source aware.
+template <int factor, int index>
+float Weight(float /*dst*/[4], float src[4], float src1[4]) {
+  if (factor == GL_SRC_COLOR)
+    return src[index];
+  if (factor == GL_SRC_ALPHA)
+    return src[3];
+  if (factor == GL_SRC1_COLOR_EXT)
+    return src1[index];
+  if (factor == GL_SRC1_ALPHA_EXT)
+    return src1[3];
+  if (factor == GL_ONE_MINUS_SRC1_COLOR_EXT)
+    return 1.0f - src1[index];
+  if (factor == GL_ONE_MINUS_SRC1_ALPHA_EXT)
+    return 1.0f - src1[3];
+  return 0.0f;
+}
+
+// Implementation of GLES 2 blend equation that is dual-source aware.
+template <int RGBs, int RGBd, int As, int Ad>
+void BlendEquationFuncAdd(float dst[4],
+                          float src[4],
+                          float src1[4],
+                          uint8 result[4]) {
+  float r[4];
+  r[0] = src[0] * Weight<RGBs, 0>(dst, src, src1) +
+         dst[0] * Weight<RGBd, 0>(dst, src, src1);
+  r[1] = src[1] * Weight<RGBs, 1>(dst, src, src1) +
+         dst[1] * Weight<RGBd, 1>(dst, src, src1);
+  r[2] = src[2] * Weight<RGBs, 2>(dst, src, src1) +
+         dst[2] * Weight<RGBd, 2>(dst, src, src1);
+  r[3] = src[3] * Weight<As, 3>(dst, src, src1) +
+         dst[3] * Weight<Ad, 3>(dst, src, src1);
+  for (int i = 0; i < 4; ++i) {
+    result[i] = static_cast<uint8>(
+        std::floor(std::max(0.0f, std::min(1.0f, r[i])) * 255.0f));
+  }
+}
+
+}  // namespace
+
+namespace gpu {
+
+class EXTBlendFuncExtendedTest : public testing::Test {
+ public:
+ protected:
+  void SetUp() override { gl_.Initialize(GLManager::Options()); }
+
+  void TearDown() override { gl_.Destroy(); }
+  bool IsApplicable() const {
+    return GLTestHelper::HasExtension("GL_EXT_blend_func_extended");
+  }
+  GLManager gl_;
+};
+
+TEST_F(EXTBlendFuncExtendedTest, TestMaxDualSourceDrawBuffers) {
+  if (!IsApplicable())
+    return;
+
+  GLint maxDualSourceDrawBuffers = 0;
+  glGetIntegerv(GL_MAX_DUAL_SOURCE_DRAW_BUFFERS_EXT, &maxDualSourceDrawBuffers);
+  EXPECT_GT(maxDualSourceDrawBuffers, 0);
+  EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
+}
+
+class EXTBlendFuncExtendedDrawTest : public testing::TestWithParam<bool> {
+ public:
+  static const GLsizei kWidth = 100;
+  static const GLsizei kHeight = 100;
+  EXTBlendFuncExtendedDrawTest() : program_(0) {}
+
+ protected:
+  void SetUp() override {
+    GLManager::Options options;
+    options.size = gfx::Size(kWidth, kHeight);
+    options.force_shader_name_hashing = GetParam();
+    base::CommandLine command_line(*base::CommandLine::ForCurrentProcess());
+    gl_.InitializeWithCommandLine(options, &command_line);
+  }
+
+  bool IsApplicable() const {
+    return GLTestHelper::HasExtension("GL_EXT_blend_func_extended");
+  }
+
+  virtual const char* GetVertexShader() {
+    // clang-format off
+    static const char* kVertexShader =
+        SHADER(
+            attribute vec4 position;
+            void main() {
+              gl_Position = position;
+            });
+    // clang-format on
+    return kVertexShader;
+  }
+
+  void CreateProgramWithFragmentShader(const char* fragment_shader_str) {
+    GLuint vertex_shader =
+        GLTestHelper::LoadShader(GL_VERTEX_SHADER, GetVertexShader());
+    GLuint fragment_shader =
+        GLTestHelper::LoadShader(GL_FRAGMENT_SHADER, fragment_shader_str);
+    ASSERT_NE(0u, vertex_shader);
+    ASSERT_NE(0u, fragment_shader);
+    program_ = glCreateProgram();
+    ASSERT_NE(0u, program_);
+    glAttachShader(program_, vertex_shader);
+    glAttachShader(program_, fragment_shader);
+    glDeleteShader(vertex_shader);
+    glDeleteShader(fragment_shader);
+  }
+
+  testing::AssertionResult LinkProgram() {
+    glLinkProgram(program_);
+    GLint linked = 0;
+    glGetProgramiv(program_, GL_LINK_STATUS, &linked);
+    if (linked == 0) {
+      char buffer[1024];
+      GLsizei length = 0;
+      glGetProgramInfoLog(program_, sizeof(buffer), &length, buffer);
+      std::string log(buffer, length);
+      return testing::AssertionFailure() << "Error linking program: " << log;
+    }
+    glUseProgram(program_);
+    position_loc_ = glGetAttribLocation(program_, "position");
+    src_loc_ = glGetUniformLocation(program_, "src");
+    src1_loc_ = glGetUniformLocation(program_, "src1");
+    return testing::AssertionSuccess();
+  }
+
+  void TearDown() override {
+    if (program_ != 0)
+      glDeleteProgram(program_);
+    gl_.Destroy();
+  }
+
+  void DrawAndVerify() {
+    float kDst[4] = {0.5f, 0.5f, 0.5f, 0.5f};
+    float kSrc[4] = {1.0f, 1.0f, 1.0f, 1.0f};
+    float kSrc1[4] = {0.3f, 0.6f, 0.9f, 0.7f};
+
+    glUniform4f(src_loc_, kSrc[0], kSrc[1], kSrc[2], kSrc[3]);
+    glUniform4f(src1_loc_, kSrc1[0], kSrc1[1], kSrc1[2], kSrc1[3]);
+
+    GLTestHelper::SetupUnitQuad(position_loc_);
+
+    glEnable(GL_BLEND);
+    glBlendEquation(GL_FUNC_ADD);
+    glBlendFuncSeparate(GL_SRC1_COLOR_EXT, GL_SRC_ALPHA,
+                        GL_ONE_MINUS_SRC1_COLOR_EXT,
+                        GL_ONE_MINUS_SRC1_ALPHA_EXT);
+    EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
+
+    // Draw one triangle (bottom left half).
+    glViewport(0, 0, kWidth, kHeight);
+    glClearColor(kDst[0], kDst[1], kDst[2], kDst[3]);
+    glClear(GL_COLOR_BUFFER_BIT);
+    glDrawArrays(GL_TRIANGLES, 0, 6);
+    EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
+    // Verify.
+    uint8 color[4];
+    BlendEquationFuncAdd<GL_SRC1_COLOR_EXT, GL_SRC_ALPHA,
+                         GL_ONE_MINUS_SRC1_COLOR_EXT,
+                         GL_ONE_MINUS_SRC1_ALPHA_EXT>(kDst, kSrc, kSrc1, color);
+
+    EXPECT_TRUE(GLTestHelper::CheckPixels(kWidth / 4, (3 * kHeight) / 4, 1, 1,
+                                          1, color));
+    EXPECT_TRUE(GLTestHelper::CheckPixels(kWidth - 1, 0, 1, 1, 1, color));
+  }
+
+ protected:
+  GLuint program_;
+  GLuint position_loc_;
+  GLuint src_loc_;
+  GLuint src1_loc_;
+  GLManager gl_;
+};
+
+TEST_P(EXTBlendFuncExtendedDrawTest, ESSL1FragColor) {
+  if (!IsApplicable())
+    return;
+  // clang-format off
+  static const char* kFragColorShader =
+      BFE_SHADER(
+          precision mediump float;
+          uniform vec4 src;
+          uniform vec4 src1;
+          void main() {
+            gl_FragColor = src;
+            gl_SecondaryFragColorEXT = src1;
+          });
+  // clang-format on
+  CreateProgramWithFragmentShader(kFragColorShader);
+  LinkProgram();
+  DrawAndVerify();
+}
+
+TEST_P(EXTBlendFuncExtendedDrawTest, ESSL1FragData) {
+  if (!IsApplicable())
+    return;
+  // clang-format off
+  static const char* kFragDataShader =
+      BFE_SHADER(
+          precision mediump float;
+          uniform vec4 src;
+          uniform vec4 src1;
+          void main() {
+            gl_FragData[0] = src;
+            gl_SecondaryFragDataEXT[0] = src1;
+          });
+  // clang-format on
+  CreateProgramWithFragmentShader(kFragDataShader);
+  LinkProgram();
+  DrawAndVerify();
+}
+
+class EXTBlendFuncExtendedES3DrawTest : public EXTBlendFuncExtendedDrawTest {
+ protected:
+  void SetUp() override {
+    GLManager::Options options;
+    options.size = gfx::Size(kWidth, kHeight);
+    options.context_type = gles2::CONTEXT_TYPE_OPENGLES3;
+    options.force_shader_name_hashing = GetParam();
+    base::CommandLine command_line(*base::CommandLine::ForCurrentProcess());
+    command_line.AppendSwitch(switches::kEnableUnsafeES3APIs);
+    gl_.InitializeWithCommandLine(options, &command_line);
+  }
+  bool IsApplicable() const {
+    return gl_.IsInitialized() && EXTBlendFuncExtendedDrawTest::IsApplicable();
+  }
+  const char* GetVertexShader() override {
+    // clang-format off
+    static const char* kVertexShader =
+        "#version 300 es\n"
+        SHADER(
+            in vec4 position;
+            void main() {
+              gl_Position = position;
+            });
+    // clang-format on
+    return kVertexShader;
+  }
+};
+
+TEST_P(EXTBlendFuncExtendedES3DrawTest, ESSL3Var) {
+  if (!IsApplicable())
+    return;
+  // clang-format off
+  static const char* kFragColorShader =
+      "#version 300 es\n"
+      BFE_SHADER(
+          precision mediump float;
+          uniform vec4 src;
+          uniform vec4 src1;
+          out vec4 FragColor;
+          out vec4 SecondaryFragColor;
+          void main() {
+            FragColor = src;
+            SecondaryFragColor = src1;
+          });
+  // clang-format on
+  CreateProgramWithFragmentShader(kFragColorShader);
+  glBindFragDataLocationIndexedEXT(program_, 0, 1, "SecondaryFragColor");
+  LinkProgram();
+  DrawAndVerify();
+}
+
+TEST_P(EXTBlendFuncExtendedES3DrawTest, ESSL3BindArrayWithSimpleName) {
+  if (!IsApplicable())
+    return;
+  // clang-format off
+  static const char* kFragDataShader =
+      "#version 300 es\n"
+      BFE_SHADER(
+          precision mediump float;
+          uniform vec4 src;
+          uniform vec4 src1;
+          out vec4 FragData[1];
+          out vec4 SecondaryFragData[1];
+          void main() {
+            FragData[0] = src;
+            SecondaryFragData[0] = src1;
+          });
+  // clang-format on
+  CreateProgramWithFragmentShader(kFragDataShader);
+  glBindFragDataLocationEXT(program_, 0, "FragData");
+  glBindFragDataLocationIndexedEXT(program_, 0, 1, "SecondaryFragData");
+  LinkProgram();
+  DrawAndVerify();
+}
+
+TEST_P(EXTBlendFuncExtendedES3DrawTest, ESSL3BindSimpleVarAsArrayNoBind) {
+  if (!IsApplicable())
+    return;
+  // clang-format off
+  static const char* kFragDataShader =
+      "#version 300 es\n"
+      BFE_SHADER(
+          precision mediump float;
+          uniform vec4 src;
+          uniform vec4 src1;
+          out vec4 FragData;
+          out vec4 SecondaryFragData;
+          void main() {
+            FragData = src;
+            SecondaryFragData = src1;
+          });
+  // clang-format on
+  CreateProgramWithFragmentShader(kFragDataShader);
+  glBindFragDataLocationEXT(program_, 0, "FragData[0]");
+  glBindFragDataLocationIndexedEXT(program_, 0, 1, "SecondaryFragData[0]");
+  // Does not fail, since FragData[0] and SecondaryFragData[0] do not exist.
+  EXPECT_TRUE(LinkProgram());
+
+  EXPECT_EQ(-1, glGetFragDataLocation(program_, "FragData[0]"));
+  EXPECT_EQ(0, glGetFragDataLocation(program_, "FragData"));
+  EXPECT_EQ(1, glGetFragDataLocation(program_, "SecondaryFragData"));
+  // Did not bind index.
+  EXPECT_EQ(0, glGetFragDataIndexEXT(program_, "SecondaryFragData"));
+
+  glBindFragDataLocationEXT(program_, 0, "FragData");
+  glBindFragDataLocationIndexedEXT(program_, 0, 1, "SecondaryFragData");
+  EXPECT_TRUE(LinkProgram());
+  DrawAndVerify();
+}
+
+TEST_P(EXTBlendFuncExtendedES3DrawTest, ESSL3BindArrayAsArray) {
+  if (!IsApplicable())
+    return;
+  // clang-format off
+  static const char* kFragDataShader =
+      "#version 300 es\n"
+      BFE_SHADER(
+          precision mediump float;
+          uniform vec4 src;
+          uniform vec4 src1;
+          out vec4 FragData[1];
+          out vec4 SecondaryFragData[1];
+          void main() {
+            FragData[0] = src;
+            SecondaryFragData[0] = src1;
+          });
+  // clang-format on
+  CreateProgramWithFragmentShader(kFragDataShader);
+  glBindFragDataLocationEXT(program_, 0, "FragData[0]");
+  glBindFragDataLocationIndexedEXT(program_, 0, 1, "SecondaryFragData[0]");
+  LinkProgram();
+  DrawAndVerify();
+}
+
+TEST_P(EXTBlendFuncExtendedES3DrawTest, ES3Getters) {
+  if (!IsApplicable())
+    return;
+  // clang-format off
+  static const char* kFragColorShader =
+      "#version 300 es\n"
+      BFE_SHADER(
+          precision mediump float;
+          uniform vec4 src;
+          uniform vec4 src1;
+          out vec4 FragColor;
+          out vec4 SecondaryFragColor;
+          void main() {
+            FragColor = src;
+            SecondaryFragColor = src1;
+          });
+  // clang-format on
+  CreateProgramWithFragmentShader(kFragColorShader);
+  glBindFragDataLocationEXT(program_, 0, "FragColor");
+  glBindFragDataLocationIndexedEXT(program_, 0, 1, "SecondaryFragColor");
+
+  // Getters return GL error before linking.
+  EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
+  GLint location = glGetFragDataLocation(program_, "FragColor");
+  EXPECT_EQ(static_cast<GLenum>(GL_INVALID_OPERATION), glGetError());
+  GLint index = glGetFragDataIndexEXT(program_, "FragColor");
+  EXPECT_EQ(static_cast<GLenum>(GL_INVALID_OPERATION), glGetError());
+  location = glGetFragDataLocation(program_, "SecondaryFragColor");
+  EXPECT_EQ(static_cast<GLenum>(GL_INVALID_OPERATION), glGetError());
+  index = glGetFragDataIndexEXT(program_, "SecondaryFragColor");
+  EXPECT_EQ(static_cast<GLenum>(GL_INVALID_OPERATION), glGetError());
+  LinkProgram();
+
+  // Getters return location and index after linking. Run twice to confirm that
+  // setters do not affect the getters until next link.
+  for (int i = 0; i < 2; ++i) {
+    SCOPED_TRACE(testing::Message() << "Testing getters after link, iteration "
+                                    << i);
+
+    location = glGetFragDataLocation(program_, "FragColor");
+    EXPECT_EQ(0, location);
+    EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
+    index = glGetFragDataIndexEXT(program_, "FragColor");
+    EXPECT_EQ(0, index);
+    EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
+    location = glGetFragDataLocation(program_, "SecondaryFragColor");
+    EXPECT_EQ(0, location);
+    EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
+    index = glGetFragDataIndexEXT(program_, "SecondaryFragColor");
+    EXPECT_EQ(1, index);
+    EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
+
+    // The calls should not affect the getters until re-linking.
+    glBindFragDataLocationEXT(program_, 0, "SecondaryFragColor");
+    glBindFragDataLocationIndexedEXT(program_, 0, 1, "FragColor");
+  }
+
+  LinkProgram();
+
+  location = glGetFragDataLocation(program_, "FragColor");
+  EXPECT_EQ(0, location);
+  EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
+  index = glGetFragDataIndexEXT(program_, "FragColor");
+  EXPECT_EQ(1, index);
+  EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
+  location = glGetFragDataLocation(program_, "SecondaryFragColor");
+  EXPECT_EQ(0, location);
+  EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
+  index = glGetFragDataIndexEXT(program_, "SecondaryFragColor");
+  EXPECT_EQ(0, index);
+  EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
+
+  // Unknown colors return location -1, index -1.
+  location = glGetFragDataLocation(program_, "UnknownColor");
+  EXPECT_EQ(-1, location);
+  EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
+  index = glGetFragDataIndexEXT(program_, "UnknownColor");
+  EXPECT_EQ(-1, index);
+
+  // Reset the settings and verify that the driver gets them correct.
+  glBindFragDataLocationEXT(program_, 0, "FragColor");
+  glBindFragDataLocationIndexedEXT(program_, 0, 1, "SecondaryFragColor");
+  LinkProgram();
+  DrawAndVerify();
+}
+
+// Test that tests glBindFragDataLocationEXT, glBindFragDataLocationIndexedEXT,
+// glGetFragDataLocation, glGetFragDataIndexEXT work correctly with
+// GLSL array output variables. The output variable can be bound by
+// referring to the variable name with or without the first element array
+// accessor. The getters can query location of the individual elements in
+// the array. The test does not actually use the base test drawing,
+// since the drivers at the time of writing do not support multiple
+// buffers and dual source blending.
+TEST_P(EXTBlendFuncExtendedES3DrawTest, ES3GettersArray) {
+  if (!IsApplicable())
+    return;
+  const GLint kTestArraySize = 2;
+  const GLint kFragData0Location = 2;
+  const GLint kFragData1Location = 1;
+  const GLint kUnusedLocation = 5;
+
+  // The test binds kTestArraySize -sized array to location 1 for test purposes.
+  // The GL_MAX_DRAW_BUFFERS must be > kTestArraySize, since an
+  // array will be bound to continuous locations, starting from the first
+  // location.
+  GLint maxDrawBuffers = 0;
+  glGetIntegerv(GL_MAX_DRAW_BUFFERS_EXT, &maxDrawBuffers);
+  EXPECT_LT(kTestArraySize, maxDrawBuffers);
+
+  // clang-format off
+  static const char* kFragColorShader =
+      "#version 300 es\n"
+      BFE_SHADER(
+          precision mediump float;
+          uniform vec4 src;
+          uniform vec4 src1;
+          out vec4 FragData[2];
+          void main() {
+            FragData[0] = src;
+            FragData[1] = src1;
+          });
+  // clang-format on
+  CreateProgramWithFragmentShader(kFragColorShader);
+
+  for (int testcase = 0; testcase < 4; ++testcase) {
+    if (testcase == 0) {
+      glBindFragDataLocationEXT(program_, kUnusedLocation, "FragData[0]");
+      glBindFragDataLocationEXT(program_, kFragData0Location, "FragData");
+      glBindFragDataLocationEXT(program_, kFragData1Location, "FragData[1]");
+    } else if (testcase == 1) {
+      glBindFragDataLocationEXT(program_, kUnusedLocation, "FragData");
+      glBindFragDataLocationEXT(program_, kFragData0Location, "FragData[0]");
+      glBindFragDataLocationEXT(program_, kFragData1Location, "FragData[1]");
+    } else if (testcase == 2) {
+      glBindFragDataLocationIndexedEXT(program_, kUnusedLocation, 0,
+                                       "FragData[0]");
+      glBindFragDataLocationIndexedEXT(program_, kFragData0Location, 0,
+                                       "FragData");
+      glBindFragDataLocationIndexedEXT(program_, kFragData1Location, 0,
+                                       "FragData[1]");
+    } else if (testcase == 3) {
+      glBindFragDataLocationIndexedEXT(program_, kUnusedLocation, 0,
+                                       "FragData");
+      glBindFragDataLocationIndexedEXT(program_, kFragData0Location, 0,
+                                       "FragData[0]");
+      glBindFragDataLocationIndexedEXT(program_, kFragData1Location, 0,
+                                       "FragData[1]");
+    }
+
+    EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
+    LinkProgram();
+    EXPECT_EQ(kFragData0Location, glGetFragDataLocation(program_, "FragData"));
+    EXPECT_EQ(0, glGetFragDataIndexEXT(program_, "FragData"));
+    EXPECT_EQ(kFragData0Location,
+              glGetFragDataLocation(program_, "FragData[0]"));
+    EXPECT_EQ(0, glGetFragDataIndexEXT(program_, "FragData[0]"));
+    EXPECT_EQ(kFragData1Location,
+              glGetFragDataLocation(program_, "FragData[1]"));
+    EXPECT_EQ(0, glGetFragDataIndexEXT(program_, "FragData[1]"));
+
+    // Index bigger than the GLSL variable array length does not find anything.
+    EXPECT_EQ(-1, glGetFragDataLocation(program_, "FragData[3]"));
+  }
+}
+
+// Test that tests glBindFragDataLocationEXT, glBindFragDataLocationIndexedEXT
+// conflicts
+// with GLSL output variables.
+TEST_P(EXTBlendFuncExtendedES3DrawTest, ES3Conflicts) {
+  if (!IsApplicable())
+    return;
+  const GLint kTestArraySize = 2;
+  const GLint kColorName0Location = 0;
+  const GLint kColorName1Location = 1;
+  GLint maxDrawBuffers = 0;
+  glGetIntegerv(GL_MAX_DRAW_BUFFERS_EXT, &maxDrawBuffers);
+  EXPECT_LT(kTestArraySize, maxDrawBuffers);
+
+  // clang-format off
+  static const char* kFragColorShader =
+      "#version 300 es\n"
+      BFE_SHADER(
+          precision mediump float;
+          uniform vec4 src;
+          uniform vec4 src1;
+          out vec4 FragData0;
+          out vec4 FragData1;
+          void main() {
+            FragData0 = src;
+            FragData1 = src1;
+          });
+  // clang-format on
+  CreateProgramWithFragmentShader(kFragColorShader);
+
+  glBindFragDataLocationEXT(program_, kColorName0Location, "FragData0");
+  glBindFragDataLocationEXT(program_, kColorName0Location, "FragData1");
+  EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
+  EXPECT_FALSE(LinkProgram());
+
+  glBindFragDataLocationIndexedEXT(program_, kColorName0Location, 0,
+                                   "FragData0");
+  glBindFragDataLocationIndexedEXT(program_, kColorName0Location, 0,
+                                   "FragData1");
+  EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
+  EXPECT_FALSE(LinkProgram());
+
+  glBindFragDataLocationIndexedEXT(program_, kColorName0Location, 1,
+                                   "FragData0");
+  glBindFragDataLocationIndexedEXT(program_, kColorName0Location, 1,
+                                   "FragData1");
+  EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
+  EXPECT_FALSE(LinkProgram());
+
+  // Test that correct binding actually works.
+  glBindFragDataLocationEXT(program_, kColorName0Location, "FragData0");
+  glBindFragDataLocationEXT(program_, kColorName1Location, "FragData1");
+  EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
+  EXPECT_TRUE(LinkProgram());
+
+  glBindFragDataLocationIndexedEXT(program_, kColorName0Location, 0,
+                                   "FragData0");
+  glBindFragDataLocationIndexedEXT(program_, kColorName0Location, 1,
+                                   "FragData1");
+  EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
+  EXPECT_TRUE(LinkProgram());
+}
+
+// Test that tests glBindFragDataLocationEXT conflicts
+// with GLSL array output variables.
+TEST_P(EXTBlendFuncExtendedES3DrawTest, ES3ConflictsArray) {
+  if (!IsApplicable())
+    return;
+  const GLint kTestArraySize = 2;
+  const GLint kColorName0Location = 0;
+  const GLint kColorName1Location = 1;
+  const GLint kUnusedLocation = 5;
+  GLint maxDrawBuffers = 0;
+  glGetIntegerv(GL_MAX_DRAW_BUFFERS_EXT, &maxDrawBuffers);
+  EXPECT_LT(kTestArraySize, maxDrawBuffers);
+
+  // clang-format off
+  static const char* kFragColorShader =
+      "#version 300 es\n"
+      BFE_SHADER(
+          precision mediump float;
+          uniform vec4 src;
+          uniform vec4 src1;
+          out vec4 FragData[2];
+          void main() {
+            FragData[0] = src;
+            FragData[1] = src1;
+          });
+  // clang-format on
+  CreateProgramWithFragmentShader(kFragColorShader);
+
+  glBindFragDataLocationEXT(program_, kColorName1Location, "FragData");
+  glBindFragDataLocationEXT(program_, kColorName1Location, "FragData[1]");
+  EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
+  EXPECT_FALSE(LinkProgram());
+  glBindFragDataLocationEXT(program_, kUnusedLocation, "FragData");
+  glBindFragDataLocationEXT(program_, kColorName1Location, "FragData[0]");
+  glBindFragDataLocationEXT(program_, kColorName1Location, "FragData[1]");
+  EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
+  EXPECT_FALSE(LinkProgram());
+  // Test that binding actually works.
+  glBindFragDataLocationEXT(program_, kColorName0Location, "FragData[0]");
+  glBindFragDataLocationEXT(program_, kColorName1Location, "FragData[1]");
+  EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
+  EXPECT_TRUE(LinkProgram());
+}
+
+INSTANTIATE_TEST_CASE_P(TranslatorVariants,
+                        EXTBlendFuncExtendedDrawTest,
+                        ::testing::Bool());
+
+INSTANTIATE_TEST_CASE_P(TranslatorVariants,
+                        EXTBlendFuncExtendedES3DrawTest,
+                        ::testing::Bool());
+
+}  // namespace gpu
diff --git a/gpu/config/gpu_info_collector.cc b/gpu/config/gpu_info_collector.cc
index 2b7eaef..beda6fd 100644
--- a/gpu/config/gpu_info_collector.cc
+++ b/gpu/config/gpu_info_collector.cc
@@ -18,6 +18,7 @@
 #include "ui/gl/gl_context.h"
 #include "ui/gl/gl_implementation.h"
 #include "ui/gl/gl_surface.h"
+#include "ui/gl/gl_version_info.h"
 
 namespace {
 
@@ -102,8 +103,24 @@
   gpu_info->gl_extensions = gfx::GetGLExtensionsFromCurrentContext();
   gpu_info->gl_version = GetGLString(GL_VERSION);
   std::string glsl_version_string = GetGLString(GL_SHADING_LANGUAGE_VERSION);
+
+  gfx::GLVersionInfo gl_info(gpu_info->gl_version.c_str(),
+                             gpu_info->gl_renderer.c_str(),
+                             gpu_info->gl_extensions.c_str());
   GLint max_samples = 0;
-  glGetIntegerv(GL_MAX_SAMPLES, &max_samples);
+  if (gl_info.IsAtLeastGL(3, 0) || gl_info.IsAtLeastGLES(3, 0) ||
+      gpu_info->gl_extensions.find("GL_ANGLE_framebuffer_multisample") !=
+          std::string::npos ||
+      gpu_info->gl_extensions.find("GL_APPLE_framebuffer_multisample") !=
+          std::string::npos ||
+      gpu_info->gl_extensions.find("GL_EXT_framebuffer_multisample") !=
+          std::string::npos ||
+      gpu_info->gl_extensions.find("GL_EXT_multisampled_render_to_texture") !=
+          std::string::npos ||
+      gpu_info->gl_extensions.find("GL_NV_framebuffer_multisample") !=
+          std::string::npos) {
+    glGetIntegerv(GL_MAX_SAMPLES, &max_samples);
+  }
   gpu_info->max_msaa_samples = base::IntToString(max_samples);
   UMA_HISTOGRAM_SPARSE_SLOWLY("GPU.MaxMSAASampleCount", max_samples);
 
diff --git a/gpu/config/gpu_info_collector_unittest.cc b/gpu/config/gpu_info_collector_unittest.cc
index 0f9b306..76fc31b2 100644
--- a/gpu/config/gpu_info_collector_unittest.cc
+++ b/gpu/config/gpu_info_collector_unittest.cc
@@ -64,7 +64,7 @@
         test_values_.gl_version = "OpenGL ES 2.0 V@14.0 AU@04.02 (CL@3206)";
         test_values_.gl_extensions =
             "GL_OES_packed_depth_stencil GL_EXT_texture_format_BGRA8888 "
-            "GL_EXT_read_format_bgra";
+            "GL_EXT_read_format_bgra GL_EXT_multisampled_render_to_texture";
         gl_shading_language_version_ = "1.00";
         break;
       }
@@ -96,7 +96,7 @@
         test_values_.gl_version = "2.1 NVIDIA-1.6.18";
         test_values_.gl_extensions =
             "GL_OES_packed_depth_stencil GL_EXT_texture_format_BGRA8888 "
-            "GL_EXT_read_format_bgra";
+            "GL_EXT_read_format_bgra GL_EXT_framebuffer_multisample";
         gl_shading_language_version_ = "1.20 ";
         break;
       }
diff --git a/gpu/gpu.gyp b/gpu/gpu.gyp
index 68aaaff..14c4ea31 100644
--- a/gpu/gpu.gyp
+++ b/gpu/gpu.gyp
@@ -367,7 +367,8 @@
         'command_buffer/tests/gl_copy_texture_CHROMIUM_unittest.cc',
         'command_buffer/tests/gl_cube_map_texture_unittest.cc',
         'command_buffer/tests/gl_depth_texture_unittest.cc',
-        'command_buffer/tests/gl_ext_multisample_compatibility_unittest.cc',	
+        'command_buffer/tests/gl_ext_blend_func_extended_unittest.cc',
+        'command_buffer/tests/gl_ext_multisample_compatibility_unittest.cc',
         'command_buffer/tests/gl_ext_srgb_unittest.cc',
         'command_buffer/tests/gl_fence_sync_unittest.cc',
         'command_buffer/tests/gl_gpu_memory_buffer_unittest.cc',
diff --git a/gpu/skia_bindings/gl_bindings_skia_cmd_buffer.cc b/gpu/skia_bindings/gl_bindings_skia_cmd_buffer.cc
index 9afc900..0203d07 100644
--- a/gpu/skia_bindings/gl_bindings_skia_cmd_buffer.cc
+++ b/gpu/skia_bindings/gl_bindings_skia_cmd_buffer.cc
@@ -143,6 +143,8 @@
     glRenderbufferStorageMultisampleCHROMIUM;
   functions->fRenderbufferStorageMultisampleES2EXT =
     glRenderbufferStorageMultisampleEXT;
+  functions->fBindFragDataLocation = glBindFragDataLocationEXT;
+  functions->fBindFragDataLocationIndexed = glBindFragDataLocationIndexedEXT;
   functions->fBindUniformLocation = glBindUniformLocationCHROMIUM;
   functions->fBlitFramebuffer = glBlitFramebufferCHROMIUM;
   functions->fGenerateMipmap = glGenerateMipmap;
diff --git a/ios/chrome/browser/about_flags.mm b/ios/chrome/browser/about_flags.mm
index 1d7b752c..81ddefc 100644
--- a/ios/chrome/browser/about_flags.mm
+++ b/ios/chrome/browser/about_flags.mm
@@ -50,12 +50,12 @@
 const flags_ui::FeatureEntry kFeatureEntries[] = {
     {"contextual-search", IDS_IOS_FLAGS_CONTEXTUAL_SEARCH,
      IDS_IOS_FLAGS_CONTEXTUAL_SEARCH_DESCRIPTION,
-     flags_ui::kOsIos | flags_ui::kOsIosAppleReview,
+     flags_ui::kOsIos,
      ENABLE_DISABLE_VALUE_TYPE(switches::kEnableContextualSearch,
                                switches::kDisableContextualSearch)},
     {"enhanced-bookmarks-experiment", IDS_FLAGS_ENHANCED_BOOKMARKS_NAME,
      IDS_FLAGS_ENHANCED_BOOKMARKS_DESCRIPTION,
-     flags_ui::kOsIos | flags_ui::kOsIosAppleReview,
+     flags_ui::kOsIos,
      ENABLE_DISABLE_VALUE_TYPE_AND_VALUE(switches::kEnhancedBookmarksExperiment,
                                          "1",
                                          switches::kEnhancedBookmarksExperiment,
diff --git a/ios/chrome/browser/experimental_flags.mm b/ios/chrome/browser/experimental_flags.mm
index 0fd40ed..29ea735 100644
--- a/ios/chrome/browser/experimental_flags.mm
+++ b/ios/chrome/browser/experimental_flags.mm
@@ -174,8 +174,10 @@
 }
 
 bool AreKeyboardCommandsEnabled() {
-  return !base::CommandLine::ForCurrentProcess()->HasSwitch(
-      switches::kDisableKeyboardCommands);
+  const base::CommandLine* command_line =
+      base::CommandLine::ForCurrentProcess();
+  return command_line &&
+         !command_line->HasSwitch(switches::kDisableKeyboardCommands);
 }
 
 bool IsViewCopyPasswordsEnabled() {
diff --git a/ios/chrome/browser/prefs/browser_prefs.mm b/ios/chrome/browser/prefs/browser_prefs.mm
index d9a0584..0bab9ac 100644
--- a/ios/chrome/browser/prefs/browser_prefs.mm
+++ b/ios/chrome/browser/prefs/browser_prefs.mm
@@ -20,6 +20,7 @@
 #include "components/rappor/rappor_service.h"
 #include "components/search_engines/template_url_prepopulate_data.h"
 #include "components/signin/core/common/signin_pref_names.h"
+#include "components/ssl_config/ssl_config_service_manager.h"
 #include "components/sync_driver/sync_prefs.h"
 #include "components/translate/core/browser/translate_prefs.h"
 #include "components/translate/core/common/translate_pref_names.h"
@@ -57,6 +58,7 @@
   network_time::NetworkTimeTracker::RegisterPrefs(registry);
   PrefProxyConfigTrackerImpl::RegisterPrefs(registry);
   rappor::RapporService::RegisterPrefs(registry);
+  ssl_config::SSLConfigServiceManager::RegisterPrefs(registry);
   variations::VariationsService::RegisterPrefs(registry);
   web_resource::PromoResourceService::RegisterPrefs(registry);
 
@@ -79,8 +81,6 @@
                                 false);
 
   ApplicationContextImpl::RegisterPrefs(registry);
-
-  ios::GetChromeBrowserProvider()->RegisterLocalState(registry);
 }
 
 void RegisterBrowserStatePrefs(user_prefs::PrefRegistrySyncable* registry) {
diff --git a/ios/chrome/browser/ui/uikit_ui_util.h b/ios/chrome/browser/ui/uikit_ui_util.h
index 6fb26cd..2223a11 100644
--- a/ios/chrome/browser/ui/uikit_ui_util.h
+++ b/ios/chrome/browser/ui/uikit_ui_util.h
@@ -51,6 +51,21 @@
 // not have an alpha channel. The scale parameter is used as a scale factor
 // for the rendering context. Using 0.0 as scale will result in the device's
 // main screen scale to be used.
+// The CaptureViewWithOption function can be used with the afterScreenUpdate
+// parameter set to YES if some changes performed in the view and/or it's
+// subtree that have not yet been part of a committed implicit transaction must
+// be reflected in the snapshot. For example, it should be used if you just
+// performed changes in the view or its subviews before calling that function
+// and wants those changes to be reflected in the snapshot.
+// The CaptureView function will perform better then the afterScreenUpdate
+// version (when set to YES). If you only need to hide subviews consider
+// selectively rendering subviews in a bitmap context using
+// drawViewHierarchyInRect:afterScreenUpdates:NO.
+// On iOS < 9 this function is slow and always behave as the
+// CaptureViewWithOption function with afterScreenUpdate set to YES.
+UIImage* CaptureViewWithOption(UIView* view,
+                               CGFloat scale,
+                               BOOL afterScreenUpdate);
 UIImage* CaptureView(UIView* view, CGFloat scale);
 
 // Converts input image and returns a grey scaled version.
diff --git a/ios/chrome/browser/ui/uikit_ui_util.mm b/ios/chrome/browser/ui/uikit_ui_util.mm
index 133e0de..c1c2504 100644
--- a/ios/chrome/browser/ui/uikit_ui_util.mm
+++ b/ios/chrome/browser/ui/uikit_ui_util.mm
@@ -150,11 +150,14 @@
   CGPathRelease(path);
 }
 
-UIImage* CaptureView(UIView* view, CGFloat scale) {
+UIImage* CaptureViewWithOption(UIView* view,
+                               CGFloat scale,
+                               BOOL afterScreenUpdate) {
   UIGraphicsBeginImageContextWithOptions(view.bounds.size, YES /* opaque */,
                                          scale);
-  if (experimental_flags::IsWKWebViewEnabled()) {
-    [view drawViewHierarchyInRect:view.bounds afterScreenUpdates:NO];
+  if (base::ios::IsRunningOnIOS9OrLater()) {
+    [view drawViewHierarchyInRect:view.bounds
+               afterScreenUpdates:afterScreenUpdate];
   } else {
     CGContext* context = UIGraphicsGetCurrentContext();
     [view.layer renderInContext:context];
@@ -164,6 +167,10 @@
   return image;
 }
 
+UIImage* CaptureView(UIView* view, CGFloat scale) {
+  return CaptureViewWithOption(view, scale, NO /* afterScreenUpdate */);
+}
+
 UIImage* GreyImage(UIImage* image) {
   DCHECK(image);
   // Grey images are always non-retina to improve memory performance.
diff --git a/ios/net/http_response_headers_util.mm b/ios/net/http_response_headers_util.mm
index 64d86b5..5d6f716 100644
--- a/ios/net/http_response_headers_util.mm
+++ b/ios/net/http_response_headers_util.mm
@@ -40,7 +40,7 @@
             [NSString stringWithFormat:kHeaderLineFormat, header_name, value];
         http_headers->AddHeader(base::SysNSStringToUTF8(header_line));
       }];
-  return http_headers.Pass();
+  return http_headers;
 }
 
 }  // namespae net
diff --git a/ios/public/provider/chrome/browser/browser_state/chrome_browser_state.cc b/ios/public/provider/chrome/browser/browser_state/chrome_browser_state.cc
index 62a46ea..1041737a1 100644
--- a/ios/public/provider/chrome/browser/browser_state/chrome_browser_state.cc
+++ b/ios/public/provider/chrome/browser/browser_state/chrome_browser_state.cc
@@ -4,6 +4,7 @@
 
 #include "ios/public/provider/chrome/browser/browser_state/chrome_browser_state.h"
 
+#include "base/files/file_path.h"
 #include "ios/public/provider/web/web_ui_ios.h"
 #include "ios/web/public/web_state/web_state.h"
 
@@ -21,4 +22,15 @@
   return FromBrowserState(web_ui->GetWebState()->GetBrowserState());
 }
 
+std::string ChromeBrowserState::GetDebugName() {
+  // The debug name is based on the state path of the original browser state
+  // to keep in sync with the meaning on other platforms.
+  std::string name =
+      GetOriginalChromeBrowserState()->GetStatePath().BaseName().MaybeAsASCII();
+  if (name.empty()) {
+    name = "UnknownBrowserState";
+  }
+  return name;
+}
+
 }  // namespace ios
diff --git a/ios/public/provider/chrome/browser/browser_state/chrome_browser_state.h b/ios/public/provider/chrome/browser/browser_state/chrome_browser_state.h
index 5a8b084a..ab7be32 100644
--- a/ios/public/provider/chrome/browser/browser_state/chrome_browser_state.h
+++ b/ios/public/provider/chrome/browser/browser_state/chrome_browser_state.h
@@ -5,6 +5,8 @@
 #ifndef IOS_PUBLIC_PROVIDER_CHROME_BROWSER_BROWSER_STATE_CHROME_BROWSER_STATE_H_
 #define IOS_PUBLIC_PROVIDER_CHROME_BROWSER_BROWSER_STATE_CHROME_BROWSER_STATE_H_
 
+#include <string>
+
 #include "base/basictypes.h"
 #include "base/callback_forward.h"
 #include "base/compiler_specific.h"
@@ -79,6 +81,9 @@
   virtual void ClearNetworkingHistorySince(base::Time time,
                                            const base::Closure& completion) = 0;
 
+  // Returns an identifier of the browser state for debugging.
+  std::string GetDebugName();
+
  protected:
   ChromeBrowserState() {}
 
diff --git a/ios/public/provider/chrome/browser/chrome_browser_provider.cc b/ios/public/provider/chrome/browser/chrome_browser_provider.cc
index 285144b6..d0127165 100644
--- a/ios/public/provider/chrome/browser/chrome_browser_provider.cc
+++ b/ios/public/provider/chrome/browser/chrome_browser_provider.cc
@@ -37,9 +37,6 @@
 void ChromeBrowserProvider::AssertBrowserContextKeyedFactoriesBuilt() {
 }
 
-void ChromeBrowserProvider::RegisterLocalState(PrefRegistrySimple* registry) {
-}
-
 void ChromeBrowserProvider::RegisterProfilePrefs(
     user_prefs::PrefRegistrySyncable* registry) {
 }
diff --git a/ios/public/provider/chrome/browser/chrome_browser_provider.h b/ios/public/provider/chrome/browser/chrome_browser_provider.h
index 4509c50..008372a 100644
--- a/ios/public/provider/chrome/browser/chrome_browser_provider.h
+++ b/ios/public/provider/chrome/browser/chrome_browser_provider.h
@@ -77,8 +77,6 @@
 
   // Asserts all iOS-specific |BrowserContextKeyedServiceFactory| are built.
   virtual void AssertBrowserContextKeyedFactoriesBuilt();
-  // Registers all prefs that will be used via the local state PrefService.
-  virtual void RegisterLocalState(PrefRegistrySimple* registry);
   // Registers all prefs that will be used via a PrefService attached to a
   // Profile.
   virtual void RegisterProfilePrefs(
diff --git a/ios/web/BUILD.gn b/ios/web/BUILD.gn
index 92b7f9c..04a7511 100644
--- a/ios/web/BUILD.gn
+++ b/ios/web/BUILD.gn
@@ -220,6 +220,8 @@
     "web_state/js/crw_js_invoke_parameter_queue.mm",
     "web_state/js/crw_js_plugin_placeholder_manager.h",
     "web_state/js/crw_js_plugin_placeholder_manager.mm",
+    "web_state/js/crw_js_post_request_loader.h",
+    "web_state/js/crw_js_post_request_loader.h",
     "web_state/js/crw_js_window_id_manager.h",
     "web_state/js/crw_js_window_id_manager.mm",
     "web_state/js/page_script_util.h",
@@ -432,6 +434,7 @@
     "web_state/js/crw_js_early_script_manager_unittest.mm",
     "web_state/js/crw_js_injection_manager_unittest.mm",
     "web_state/js/crw_js_invoke_parameter_queue_unittest.mm",
+    "web_state/js/crw_js_post_request_loader_unittest.mm",
     "web_state/js/crw_js_window_id_manager_unittest.mm",
     "web_state/js/page_script_util_unittest.mm",
     "web_state/ui/crw_static_file_web_view_unittest.mm",
diff --git a/ios/web/ios_web.gyp b/ios/web/ios_web.gyp
index dddf60a4..2aa9231 100644
--- a/ios/web/ios_web.gyp
+++ b/ios/web/ios_web.gyp
@@ -237,6 +237,8 @@
         'web_state/js/credential_util.mm',
         'web_state/js/crw_js_early_script_manager.h',
         'web_state/js/crw_js_early_script_manager.mm',
+        'web_state/js/crw_js_post_request_loader.h',
+        'web_state/js/crw_js_post_request_loader.mm',
         'web_state/js/crw_js_injection_manager.mm',
         'web_state/js/crw_js_injection_receiver.mm',
         'web_state/js/crw_js_invoke_parameter_queue.h',
@@ -421,12 +423,14 @@
         'ios_web_js_bundle_wk',
       ],
       'sources': [
+        'web_state/js/resources/post_request.js',  
         'web_state/js/resources/plugin_placeholder.js',
         'web_state/js/resources/window_id.js',
         'webui/resources/web_ui.js',
       ],
       'link_settings': {
         'mac_bundle_resources': [
+          '<(SHARED_INTERMEDIATE_DIR)/post_request.js',
           '<(SHARED_INTERMEDIATE_DIR)/plugin_placeholder.js',
           '<(SHARED_INTERMEDIATE_DIR)/window_id.js',
           '<(SHARED_INTERMEDIATE_DIR)/web_ui.js',
diff --git a/ios/web/ios_web_unittests.gyp b/ios/web/ios_web_unittests.gyp
index a88f34ae..69c03e9 100644
--- a/ios/web/ios_web_unittests.gyp
+++ b/ios/web/ios_web_unittests.gyp
@@ -62,6 +62,7 @@
         'web_state/js/crw_js_early_script_manager_unittest.mm',
         'web_state/js/crw_js_injection_manager_unittest.mm',
         'web_state/js/crw_js_invoke_parameter_queue_unittest.mm',
+        'web_state/js/crw_js_post_request_loader_unittest.mm',
         'web_state/js/crw_js_window_id_manager_unittest.mm',
         'web_state/js/page_script_util_unittest.mm',
         'web_state/ui/crw_static_file_web_view_unittest.mm',
diff --git a/ios/web/net/cert_verifier_block_adapter.cc b/ios/web/net/cert_verifier_block_adapter.cc
index a43429a..932604bd 100644
--- a/ios/web/net/cert_verifier_block_adapter.cc
+++ b/ios/web/net/cert_verifier_block_adapter.cc
@@ -23,7 +23,7 @@
   VerificationContext(scoped_refptr<net::X509Certificate> cert,
                       net::NetLog* net_log)
       : request(nullptr),
-        cert(cert.Pass()),
+        cert(std::move(cert)),
         net_log(net::BoundNetLog::Make(
             net_log,
             net::NetLog::SOURCE_IOS_WEB_VIEW_CERT_VERIFIER)) {}
diff --git a/ios/web/net/crw_cert_verification_controller.mm b/ios/web/net/crw_cert_verification_controller.mm
index 85b5a106..8089386 100644
--- a/ios/web/net/crw_cert_verification_controller.mm
+++ b/ios/web/net/crw_cert_verification_controller.mm
@@ -426,8 +426,8 @@
       return;
     }
 
-    web::CertVerifierBlockAdapter::Params params(
-        blockCert.Pass(), base::SysNSStringToUTF8(host));
+    web::CertVerifierBlockAdapter::Params params(std::move(blockCert),
+                                                 base::SysNSStringToUTF8(host));
     params.flags = self.certVerifyFlags;
     // OCSP response is not provided by iOS API.
     // CRLSets are not used, as the OS is used to make load/no-load
diff --git a/ios/web/web_state/js/crw_js_post_request_loader.h b/ios/web/web_state/js/crw_js_post_request_loader.h
new file mode 100644
index 0000000..ffcde3bc
--- /dev/null
+++ b/ios/web/web_state/js/crw_js_post_request_loader.h
@@ -0,0 +1,28 @@
+// 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.
+
+#ifndef IOS_WEB_WEB_STATE_JS_CRW_JS_POST_REQUEST_LOADER_H_
+#define IOS_WEB_WEB_STATE_JS_CRW_JS_POST_REQUEST_LOADER_H_
+
+#import <WebKit/WebKit.h>
+
+@class CRWWKScriptMessageRouter;
+
+// Class to load POST requests in a provided web view via JavaScript.
+@interface CRWJSPOSTRequestLoader : NSObject
+
+// Asynchronously loads a POST |request| in provided |webView|.
+// It temporarily installs JavaScript message routers with |messageRouter| to
+// handle HTTP errors. The |completionHandler| is called once the request has
+// been executed. In case of successful request, the passed error is nil.
+// The |completionHandler| must not be null. The |messageRouter| and |webView|
+// must not be nil. The |request| must be a POST request.
+- (void)loadPOSTRequest:(NSURLRequest*)request
+              inWebView:(WKWebView*)webView
+          messageRouter:(CRWWKScriptMessageRouter*)messageRouter
+      completionHandler:(void (^)(NSError*))completionHandler;
+
+@end
+
+#endif  // IOS_WEB_WEB_STATE_JS_CRW_JS_POST_REQUEST_LOADER_H_
diff --git a/ios/web/web_state/js/crw_js_post_request_loader.mm b/ios/web/web_state/js/crw_js_post_request_loader.mm
new file mode 100644
index 0000000..4c9eea1
--- /dev/null
+++ b/ios/web/web_state/js/crw_js_post_request_loader.mm
@@ -0,0 +1,156 @@
+// 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.
+
+#import "ios/web/web_state/js/crw_js_post_request_loader.h"
+
+#include "base/json/string_escape.h"
+#import "base/mac/scoped_nsobject.h"
+#import "base/strings/sys_string_conversions.h"
+#import "ios/web/web_state/js/page_script_util.h"
+#import "ios/web/web_state/ui/crw_wk_script_message_router.h"
+
+namespace {
+
+// Escapes characters and encloses given string in quotes for use in JavaScript.
+NSString* EscapeAndQuoteStringForJavaScript(NSString* unescapedString) {
+  std::string string = base::SysNSStringToUTF8(unescapedString);
+  return base::SysUTF8ToNSString(base::GetQuotedJSONString(string));
+}
+
+// JavaScript message handler name installed in WKWebView for request errors.
+NSString* const kErrorHandlerName = @"POSTErrorHandler";
+
+// JavaScript message handler name installed in WKWebView for successful
+// request completion.
+NSString* const kSuccessHandlerName = @"POSTSuccessHandler";
+
+}  // namespace
+
+@interface CRWJSPOSTRequestLoader () {
+  base::scoped_nsobject<NSString> _requestScript;
+}
+
+// JavaScript used to execute POST requests. Lazily instantiated.
+@property(nonatomic, copy, readonly) NSString* requestScript;
+
+// Handler for UIApplicationDidReceiveMemoryWarningNotification.
+- (void)handleMemoryWarning;
+
+// Forms a JavaScript method call to |requestScript| that executes given
+// |request|.
+- (NSString*)scriptToExecutePOSTRequest:(NSURLRequest*)request;
+
+// Converts a dictionary of HTTP request headers to a JavaScript object.
+- (NSString*)JSONForJavaScriptFromRequestHeaders:(NSDictionary*)headers;
+
+@end
+
+@implementation CRWJSPOSTRequestLoader
+
+- (instancetype)init {
+  self = [super init];
+  if (self) {
+    [[NSNotificationCenter defaultCenter]
+        addObserver:self
+           selector:@selector(handleMemoryWarning)
+               name:UIApplicationDidReceiveMemoryWarningNotification
+             object:nil];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [[NSNotificationCenter defaultCenter] removeObserver:self];
+  [super dealloc];
+}
+
+- (NSString*)requestScript {
+  if (!_requestScript) {
+    _requestScript.reset([web::GetPageScript(@"post_request") copy]);
+  }
+  return _requestScript;
+}
+
+- (void)loadPOSTRequest:(NSURLRequest*)request
+              inWebView:(WKWebView*)webView
+          messageRouter:(CRWWKScriptMessageRouter*)messageRouter
+      completionHandler:(void (^)(NSError*))completionHandler {
+  DCHECK([request.HTTPMethod isEqualToString:@"POST"]);
+  DCHECK(webView);
+  DCHECK(messageRouter);
+  DCHECK(completionHandler);
+
+  // Install error handling and success routers.
+  [messageRouter setScriptMessageHandler:^(WKScriptMessage* message) {
+    // Cleaning up script handlers.
+    [messageRouter removeScriptMessageHandlerForName:kErrorHandlerName
+                                             webView:webView];
+    [messageRouter removeScriptMessageHandlerForName:kSuccessHandlerName
+                                             webView:webView];
+    completionHandler(nil);
+  }
+                                    name:kSuccessHandlerName
+                                 webView:webView];
+
+  [messageRouter setScriptMessageHandler:^(WKScriptMessage* message) {
+    NSNumber* statusCode = message.body;
+    NSError* error = [NSError errorWithDomain:NSURLErrorDomain
+                                         code:statusCode.integerValue
+                                     userInfo:nil];
+    [messageRouter removeScriptMessageHandlerForName:kErrorHandlerName
+                                             webView:webView];
+    [messageRouter removeScriptMessageHandlerForName:kSuccessHandlerName
+                                             webView:webView];
+    completionHandler(error);
+  }
+                                    name:kErrorHandlerName
+                                 webView:webView];
+
+  NSString* HTML =
+      [NSString stringWithFormat:@"<html><script>%@%@</script></html>",
+                                 self.requestScript,
+                                 [self scriptToExecutePOSTRequest:request]];
+  [webView loadHTMLString:HTML baseURL:request.URL];
+}
+
+#pragma mark - Private methods.
+
+- (void)handleMemoryWarning {
+  // Request script can be recreated from file at any moment.
+  _requestScript.reset();
+}
+
+- (NSString*)scriptToExecutePOSTRequest:(NSURLRequest*)request {
+  NSDictionary* headers = [request allHTTPHeaderFields];
+  NSString* headerString = [self JSONForJavaScriptFromRequestHeaders:headers];
+  NSString* URLString = [[request URL] absoluteString];
+  NSString* contentType = headers[@"Content-Type"];
+  NSString* base64Data = [[request HTTPBody] base64EncodedStringWithOptions:0];
+
+  // Here |headerString| is already properly escaped when returned from
+  // -JSONForJavaScriptFromRequestHeaders:.
+  return
+      [NSString stringWithFormat:
+                    @"__crPostRequestWorkaround.runPostRequest(%@, %@, %@, %@)",
+                    EscapeAndQuoteStringForJavaScript(URLString), headerString,
+                    EscapeAndQuoteStringForJavaScript(base64Data),
+                    EscapeAndQuoteStringForJavaScript(contentType)];
+}
+
+- (NSString*)JSONForJavaScriptFromRequestHeaders:(NSDictionary*)headers {
+  if (headers) {
+    NSData* headerData =
+        [NSJSONSerialization dataWithJSONObject:headers options:0 error:nil];
+    if (headerData) {
+      // This string is properly escaped by NSJSONSerialization. It needs to
+      // have no quotes since JavaScripts takes this parameter as an
+      // Object<string, string>.
+      return [[[NSString alloc] initWithData:headerData
+                                    encoding:NSUTF8StringEncoding] autorelease];
+    }
+  }
+  return @"{}";
+}
+
+@end
diff --git a/ios/web/web_state/js/crw_js_post_request_loader_unittest.mm b/ios/web/web_state/js/crw_js_post_request_loader_unittest.mm
new file mode 100644
index 0000000..aa6a4d0
--- /dev/null
+++ b/ios/web/web_state/js/crw_js_post_request_loader_unittest.mm
@@ -0,0 +1,105 @@
+// 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.
+
+#import "ios/web/web_state/js/crw_js_post_request_loader.h"
+
+#import <WebKit/WebKit.h>
+
+#import "base/mac/foundation_util.h"
+#import "base/mac/scoped_nsobject.h"
+#include "base/strings/sys_string_conversions.h"
+#import "base/test/ios/wait_util.h"
+#include "ios/web/public/test/web_test_util.h"
+#import "ios/web/public/web_view_creation_util.h"
+#import "ios/web/test/web_test.h"
+#import "ios/web/web_state/ui/crw_wk_script_message_router.h"
+#import "testing/gtest_mac.h"
+#import "third_party/ocmock/OCMock/OCMock.h"
+
+namespace base {
+namespace {
+
+typedef web::WebTest CRWJSPOSTRequestLoaderTest;
+
+// This script takes a JavaScript blob and converts it to a base64-encoded
+// string asynchronously, then is sent to XHRSendHandler message handler.
+NSString* const kBlobToBase64StringScript =
+    @"var blobToBase64 = function(x) {"
+     "  var reader = new window.FileReader();"
+     "  reader.readAsDataURL(x);"
+     "  reader.onloadend = function() {"
+     "    base64data = reader.result;"
+     "    window.webkit.messageHandlers.XHRSendHandler.postMessage(base64data);"
+     "  };"
+     "};";
+
+// Tests that the POST request is correctly executed through XMLHttpRequest.
+TEST_F(CRWJSPOSTRequestLoaderTest, LoadsCorrectHTML) {
+  CR_TEST_REQUIRES_WK_WEB_VIEW();
+
+  // Set up necessary objects.
+  scoped_nsobject<CRWJSPOSTRequestLoader> loader(
+      [[CRWJSPOSTRequestLoader alloc] init]);
+  scoped_nsobject<WKWebView> web_view(
+      web::CreateWKWebView(CGRectZero, GetBrowserState()));
+  WKUserContentController* contentController =
+      web_view.get().configuration.userContentController;
+  scoped_nsobject<CRWWKScriptMessageRouter> messageRouter(
+      [[CRWWKScriptMessageRouter alloc]
+          initWithUserContentController:contentController]);
+
+  // Override XMLHttpRequest.send() to call kBlobToBase64StringScript.
+  __block BOOL overrideSuccessfull = NO;
+  NSString* JS = [kBlobToBase64StringScript stringByAppendingString:@";\
+      XMLHttpRequest.prototype.send = function(x) { blobToBase64(x); };"];
+  [web_view evaluateJavaScript:JS
+             completionHandler:^(id, NSError*) {
+               overrideSuccessfull = YES;
+             }];
+  base::test::ios::WaitUntilCondition(^bool {
+    return overrideSuccessfull;
+  });
+
+  NSString* post_body = @"123";
+
+  // Adds XHRSendHandler handler that checks that the POST request body is
+  // correct. Sets |complete| flag upon completion.
+  __block BOOL complete = NO;
+  void (^XHRSendHandler)(WKScriptMessage*) = ^(WKScriptMessage* message) {
+    NSString* body = base::mac::ObjCCast<NSString>(message.body);
+    NSArray* components = [body componentsSeparatedByString:@","];
+    EXPECT_EQ(components.count, 2u);
+    EXPECT_NSEQ(components[0], @"data:;base64");
+    NSData* expectedData = [post_body dataUsingEncoding:NSUTF8StringEncoding];
+    EXPECT_NSEQ(components[1], [expectedData base64EncodedStringWithOptions:0]);
+    complete = YES;
+  };
+
+  [messageRouter setScriptMessageHandler:XHRSendHandler
+                                    name:@"XHRSendHandler"
+                                 webView:web_view];
+
+  // Construct and perform the POST request.
+  NSURL* url = [NSURL URLWithString:@"http://google.com"];
+  NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:url];
+  request.HTTPMethod = @"POST";
+  request.HTTPBody = [post_body dataUsingEncoding:NSUTF8StringEncoding];
+  [loader loadPOSTRequest:request
+                inWebView:web_view
+            messageRouter:messageRouter
+        completionHandler:^(NSError*){
+        }];
+
+  // Wait until the JavaScript message handler is called.
+  base::test::ios::WaitUntilCondition(^bool {
+    return complete;
+  });
+
+  // Clean up installed script handler.
+  [messageRouter removeScriptMessageHandlerForName:@"XHRSendHandler"
+                                           webView:web_view];
+}
+
+}  // namespace
+}  // namespace base
diff --git a/ios/web/web_state/js/resources/post_request.js b/ios/web/web_state/js/resources/post_request.js
new file mode 100644
index 0000000..7f5ff25
--- /dev/null
+++ b/ios/web/web_state/js/resources/post_request.js
@@ -0,0 +1,84 @@
+// 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.
+
+// Provides a way to implement POST requests via XMLHttpRequest.
+// Works around https://bugs.webkit.org/show_bug.cgi?id=145410 on WKWebView.
+
+'use strict';
+
+goog.provide('__crPostRequestWorkaround');
+
+/**
+ * Namespace for this file.
+ */
+__crPostRequestWorkaround = {};
+
+/**
+ * Executes a POST request with given parameters and replaces document body with
+ * the response.
+ * @param {string} url The url of the request.
+ * @param {Object<string,string>} headers Request headers to include in POST.
+ * Each header value must be expressed as a key-value pair in this object.
+ * @param {string} body Request body encoded with Base64.
+ * @param {string} contentType Content-Type header value.
+ */
+__crPostRequestWorkaround.runPostRequest = function(
+    url, headers, body, contentType) {
+
+  /**
+   * Converts a Base64-encoded string to a blob.
+   * @param {string} byteCharacters Base64-encoded data string.
+   * @param {string} contentType Corresponding content type.
+   * @return {Blob} Binary representation of byteCharacters.
+   */
+  var base64ToBlob = function(byteCharacters, contentType) {
+    contentType = contentType || '';
+    var sliceSize = 512;
+    var byteArrays = [];
+    var byteCount = byteCharacters.length;
+    for (var offset = 0; offset < byteCount; offset += sliceSize) {
+      var slice = byteCharacters.slice(offset, offset + sliceSize);
+      var byteNumbers = new Array(slice.length);
+      for (var i = 0; i < slice.length; i++) {
+        byteNumbers[i] = slice.charCodeAt(i);
+      }
+      var byteArray = new Uint8Array(byteNumbers);
+      byteArrays.push(byteArray);
+    }
+    return new Blob(byteArrays, {type: contentType});
+  }
+
+  /**
+   * Creates and executes a POST request.
+   * @param {string} url The url of the request.
+   * @param {Object<string,string>} headers Request headers to include in POST.
+   * Each header value must be expressed as a key-value pair in this object.
+   * @param {string} body Request body encoded with Base64.
+   * @param {string} contentType Content-Type header value.
+   */
+  var createAndSendPostRequest = function(url, headers, body, contentType) {
+    var request = new XMLHttpRequest();
+    request.open('POST', url, false);
+    for (var key in headers) {
+      if (headers.hasOwnProperty(key)) {
+        request.setRequestHeader(key, headers[key]);
+      }
+    }
+    var blob = base64ToBlob(atob(body), contentType);
+    request.send(blob);
+    if (request.status != 200) {
+      throw request.status;
+    }
+    return request.responseText;
+  }
+
+  document.open();
+  try {
+    document.write(createAndSendPostRequest(url, headers, body, contentType));
+    window.webkit.messageHandlers.POSTSuccessHandler.postMessage("");
+  } catch(error) {
+    window.webkit.messageHandlers.POSTErrorHandler.postMessage(error);
+  }
+  document.close();
+}
diff --git a/ios/web/web_state/ui/crw_wk_script_message_router.mm b/ios/web/web_state/ui/crw_wk_script_message_router.mm
index 5699abd..0e1dfbb 100644
--- a/ios/web/web_state/ui/crw_wk_script_message_router.mm
+++ b/ios/web/web_state/ui/crw_wk_script_message_router.mm
@@ -100,8 +100,12 @@
 - (void)tryRemoveScriptMessageHandlerForName:(NSString*)messageName
                                      webView:(WKWebView*)webView {
   NSMapTable* webViewToHandlerMap = [_handlers objectForKey:messageName];
-  if (![webViewToHandlerMap objectForKey:webView])
+  id handler = [webViewToHandlerMap objectForKey:webView];
+  if (!handler)
     return;
+  // Extend the lifetime of |handler| so removeScriptMessageHandlerForName: can
+  // be called from inside of |handler|.
+  [[handler retain] autorelease];
   if (webViewToHandlerMap.count == 1) {
     [_handlers removeObjectForKey:messageName];
     [_userContentController removeScriptMessageHandlerForName:messageName];
diff --git a/ios/web/web_state/ui/crw_wk_web_view_web_controller.mm b/ios/web/web_state/ui/crw_wk_web_view_web_controller.mm
index c680bac..0b2ca998 100644
--- a/ios/web/web_state/ui/crw_wk_web_view_web_controller.mm
+++ b/ios/web/web_state/ui/crw_wk_web_view_web_controller.mm
@@ -10,7 +10,7 @@
 #include "base/ios/ios_util.h"
 #include "base/ios/weak_nsobject.h"
 #include "base/json/json_reader.h"
-#include "base/mac/objc_property_releaser.h"
+#import "base/mac/objc_property_releaser.h"
 #import "base/mac/scoped_nsobject.h"
 #include "base/macros.h"
 #include "base/metrics/histogram_macros.h"
@@ -39,6 +39,7 @@
 #import "ios/web/web_state/crw_pass_kit_downloader.h"
 #import "ios/web/web_state/error_translation_util.h"
 #include "ios/web/web_state/frame_info.h"
+#import "ios/web/web_state/js/crw_js_post_request_loader.h"
 #import "ios/web/web_state/js/crw_js_window_id_manager.h"
 #import "ios/web/web_state/ui/crw_web_controller+protected.h"
 #import "ios/web/web_state/ui/crw_wk_script_message_router.h"
@@ -187,6 +188,9 @@
   // Handles downloading PassKit data for WKWebView. Lazy initialized.
   base::scoped_nsobject<CRWPassKitDownloader> _passKitDownloader;
 
+  // Object for loading POST requests with body.
+  base::scoped_nsobject<CRWJSPOSTRequestLoader> _POSTRequestLoader;
+
   // Whether the web page is currently performing window.history.pushState or
   // window.history.replaceState
   // Set to YES on window.history.willChangeState message. To NO on
@@ -233,6 +237,15 @@
 // Downloader for PassKit files. Lazy initialized.
 @property(nonatomic, readonly) CRWPassKitDownloader* passKitDownloader;
 
+// Loads POST request with body in |_wkWebView| by constructing an HTML page
+// that executes the request through JavaScript and replaces document with the
+// result.
+// Note that this approach includes multiple body encodings and decodings, plus
+// the data is passed to |_wkWebView| on main thread.
+// This is necessary because WKWebView ignores POST request body.
+// Workaround for https://bugs.webkit.org/show_bug.cgi?id=145410
+- (void)loadPOSTRequest:(NSMutableURLRequest*)request;
+
 // Returns the WKWebViewConfigurationProvider associated with the web
 // controller's BrowserState.
 - (web::WKWebViewConfigurationProvider&)webViewConfigurationProvider;
@@ -557,20 +570,42 @@
 
 - (void)loadRequestForCurrentNavigationItem {
   DCHECK(self.webView && !self.nativeController);
+  DCHECK([self currentSessionEntry]);
+
+  web::WKBackForwardListItemHolder* holder =
+      [self currentBackForwardListItemHolder];
+  BOOL isFormResubmission =
+      (holder->navigation_type() == WKNavigationTypeFormResubmitted ||
+       holder->navigation_type() == WKNavigationTypeFormSubmitted);
+  web::NavigationItemImpl* currentItem =
+      [self currentSessionEntry].navigationItemImpl;
+  NSData* POSTData = currentItem->GetPostData();
+  NSMutableURLRequest* request = [self requestForCurrentNavigationItem];
+
+  // If the request has POST data and is not a form resubmission, configure and
+  // run the POST request.
+  if (POSTData.length && !isFormResubmission) {
+    [request setHTTPMethod:@"POST"];
+    [request setHTTPBody:POSTData];
+    [request setAllHTTPHeaderFields:[self currentHTTPHeaders]];
+    [self registerLoadRequest:[self currentNavigationURL]
+                     referrer:[self currentSessionEntryReferrer]
+                   transition:[self currentTransition]];
+    [self loadPOSTRequest:request];
+    return;
+  }
 
   ProceduralBlock defaultNavigationBlock = ^{
     [self registerLoadRequest:[self currentNavigationURL]
                      referrer:[self currentSessionEntryReferrer]
                    transition:[self currentTransition]];
-    [self loadRequest:[self requestForCurrentNavigationItem]];
+    [self loadRequest:request];
   };
 
   // If there is no corresponding WKBackForwardListItem, or the item is not in
   // the current WKWebView's back-forward list, navigating using WKWebView API
   // is not possible. In this case, fall back to the default navigation
   // mechanism.
-  web::WKBackForwardListItemHolder* holder =
-      [self currentBackForwardListItemHolder];
   if (!holder->back_forward_list_item() ||
       ![self isBackForwardListItemValid:holder->back_forward_list_item()]) {
     defaultNavigationBlock();
@@ -594,10 +629,8 @@
 
   // If the request is not a form submission or resubmission, or the user
   // doesn't need to confirm the load, then continue right away.
-  web::NavigationItemImpl* currentItem =
-      [self currentSessionEntry].navigationItemImpl;
-  if ((holder->navigation_type() != WKNavigationTypeFormResubmitted &&
-       holder->navigation_type() != WKNavigationTypeFormSubmitted) ||
+
+  if (!isFormResubmission ||
       currentItem->ShouldSkipResubmitDataConfirmation()) {
     webViewNavigationBlock();
     return;
@@ -605,6 +638,7 @@
 
   // If the request is form submission or resubmission, then prompt the
   // user before proceeding.
+  DCHECK(isFormResubmission);
   [self.delegate webController:self
       onFormResubmissionForRequest:nil
                      continueBlock:webViewNavigationBlock
@@ -715,6 +749,25 @@
   return self.webStateImpl->GetRequestTracker()->identifier();
 }
 
+- (void)loadPOSTRequest:(NSMutableURLRequest*)request {
+  if (!_POSTRequestLoader) {
+    _POSTRequestLoader.reset([[CRWJSPOSTRequestLoader alloc] init]);
+  }
+
+  CRWWKScriptMessageRouter* messageRouter =
+      [self webViewConfigurationProvider].GetScriptMessageRouter();
+
+  [_POSTRequestLoader loadPOSTRequest:request
+                            inWebView:_wkWebView
+                        messageRouter:messageRouter
+                    completionHandler:^(NSError* loadError) {
+                      if (loadError)
+                        [self handleLoadError:loadError inMainFrame:YES];
+                      else
+                        self.webStateImpl->SetContentsMimeType("text/html");
+                    }];
+}
+
 - (web::WKWebViewConfigurationProvider&)webViewConfigurationProvider {
   DCHECK(self.webStateImpl);
   web::BrowserState* browserState = self.webStateImpl->GetBrowserState();
diff --git a/ipc/attachment_broker_privileged.h b/ipc/attachment_broker_privileged.h
index a82d581a..023927a 100644
--- a/ipc/attachment_broker_privileged.h
+++ b/ipc/attachment_broker_privileged.h
@@ -85,6 +85,11 @@
     // The broker did not have a channel of communication with the source
     // process.
     ERROR_SOURCE_NOT_FOUND = 12,
+    // The broker could not open the source or destination process with extra
+    // privileges.
+    ERROR_COULD_NOT_OPEN_SOURCE_OR_DEST = 13,
+    // The broker was asked to transfer a HANDLE with invalid permissions.
+    ERROR_INVALID_PERMISSIONS = 14,
     ERROR_MAX
   };
 
diff --git a/ipc/attachment_broker_privileged_win.cc b/ipc/attachment_broker_privileged_win.cc
index ec849409..38b2e652 100644
--- a/ipc/attachment_broker_privileged_win.cc
+++ b/ipc/attachment_broker_privileged_win.cc
@@ -82,6 +82,7 @@
 
   // Another process is the destination.
   base::ProcessId dest = wire_format.destination_process;
+  base::AutoLock auto_lock(*get_lock());
   Sender* sender = GetSenderWithProcessId(dest);
   if (!sender) {
     // Assuming that this message was not sent from a malicious process, the
@@ -101,35 +102,41 @@
 AttachmentBrokerPrivilegedWin::DuplicateWinHandle(
     const HandleWireFormat& wire_format,
     base::ProcessId source_pid) {
+  // If the source process is the destination process, then no additional work
+  // is required.
+  if (source_pid == wire_format.destination_process)
+    return wire_format;
+
   base::Process source_process =
       base::Process::OpenWithExtraPrivileges(source_pid);
   base::Process dest_process =
       base::Process::OpenWithExtraPrivileges(wire_format.destination_process);
-  int new_wire_format_handle = 0;
-  if (source_process.Handle() && dest_process.Handle()) {
-    DWORD desired_access = 0;
-    DWORD options = 0;
-    switch (wire_format.permissions) {
-      case HandleWin::INVALID:
-        LOG(ERROR) << "Received invalid permissions for duplication.";
-        return CopyWireFormat(wire_format, 0);
-      case HandleWin::DUPLICATE:
-        options = DUPLICATE_SAME_ACCESS;
-        break;
-      case HandleWin::FILE_READ_WRITE:
-        desired_access = FILE_GENERIC_READ | FILE_GENERIC_WRITE;
-        break;
-    }
-
-    HANDLE new_handle;
-    HANDLE original_handle = LongToHandle(wire_format.handle);
-    DWORD result = ::DuplicateHandle(source_process.Handle(), original_handle,
-                                     dest_process.Handle(), &new_handle,
-                                     desired_access, FALSE, options);
-
-    new_wire_format_handle = (result != 0) ? HandleToLong(new_handle) : 0;
+  if (!source_process.Handle() || !dest_process.Handle()) {
+    LogError(ERROR_COULD_NOT_OPEN_SOURCE_OR_DEST);
+    return wire_format;
   }
 
+  DWORD desired_access = 0;
+  DWORD options = DUPLICATE_CLOSE_SOURCE;
+  switch (wire_format.permissions) {
+    case HandleWin::INVALID:
+      LogError(ERROR_INVALID_PERMISSIONS);
+      return CopyWireFormat(wire_format, 0);
+    case HandleWin::DUPLICATE:
+      options |= DUPLICATE_SAME_ACCESS;
+      break;
+    case HandleWin::FILE_READ_WRITE:
+      desired_access = FILE_GENERIC_READ | FILE_GENERIC_WRITE;
+      break;
+  }
+
+  HANDLE new_handle;
+  HANDLE original_handle = LongToHandle(wire_format.handle);
+  DWORD result = ::DuplicateHandle(source_process.Handle(), original_handle,
+                                   dest_process.Handle(), &new_handle,
+                                   desired_access, FALSE, options);
+
+  int new_wire_format_handle = (result != 0) ? HandleToLong(new_handle) : 0;
   return CopyWireFormat(wire_format, new_wire_format_handle);
 }
 
diff --git a/ipc/attachment_broker_privileged_win_unittest.cc b/ipc/attachment_broker_privileged_win_unittest.cc
index b5e1e98..583050c 100644
--- a/ipc/attachment_broker_privileged_win_unittest.cc
+++ b/ipc/attachment_broker_privileged_win_unittest.cc
@@ -115,6 +115,13 @@
   return success;
 }
 
+// Returns 0 on error.
+DWORD GetCurrentProcessHandleCount() {
+  DWORD handle_count = 0;
+  BOOL success = ::GetProcessHandleCount(::GetCurrentProcess(), &handle_count);
+  return success ? handle_count : 0;
+}
+
 enum TestResult {
   RESULT_UNKNOWN,
   RESULT_SUCCESS,
@@ -230,9 +237,14 @@
     broker_->DesignateBrokerCommunicationChannel(channel());
     ASSERT_TRUE(ConnectChannel());
     ASSERT_TRUE(StartClient());
+
+    handle_count_ = GetCurrentProcessHandleCount();
+    EXPECT_NE(handle_count_, 0u);
   }
 
   void CommonTearDown() {
+    EXPECT_EQ(handle_count_, handle_count_);
+
     // Close the channel so the client's OnChannelError() gets fired.
     channel()->Close();
 
@@ -268,6 +280,7 @@
   ProxyListener proxy_listener_;
   scoped_ptr<IPC::AttachmentBrokerUnprivilegedWin> broker_;
   MockObserver observer_;
+  DWORD handle_count_;
 };
 
 // A broker which always sets the current process as the destination process
@@ -288,7 +301,7 @@
 // file HANDLE is sent to the privileged process using the attachment broker.
 // The privileged process dups the HANDLE into its own HANDLE table. This test
 // checks that the file has the same contents in the privileged process.
-TEST_F(IPCAttachmentBrokerPrivilegedWinTest, DISABLED_SendHandle) {
+TEST_F(IPCAttachmentBrokerPrivilegedWinTest, SendHandle) {
   Init("SendHandle");
 
   CommonSetUp();
@@ -310,7 +323,7 @@
 // Similar to SendHandle, except the file HANDLE attached to the message has
 // neither read nor write permissions.
 TEST_F(IPCAttachmentBrokerPrivilegedWinTest,
-       DISABLED_SendHandleWithoutPermissions) {
+       SendHandleWithoutPermissions) {
   Init("SendHandleWithoutPermissions");
 
   CommonSetUp();
@@ -338,7 +351,7 @@
 // Similar to SendHandle, except the attachment's destination process is this
 // process. This is an unrealistic scenario, but simulates an unprivileged
 // process sending an attachment to another unprivileged process.
-TEST_F(IPCAttachmentBrokerPrivilegedWinTest, DISABLED_SendHandleToSelf) {
+TEST_F(IPCAttachmentBrokerPrivilegedWinTest, SendHandleToSelf) {
   Init("SendHandleToSelf");
 
   set_broker(new MockBroker);
@@ -358,12 +371,11 @@
   get_broker()->GetAttachmentWithId(*id, &received_attachment);
   ASSERT_NE(received_attachment.get(), nullptr);
 
-  // Check that it's a new entry in the HANDLE table.
+  // Check that it's the same entry in the HANDLE table.
   HANDLE h2 = GetHandleFromBrokeredAttachment(received_attachment);
-  EXPECT_NE(h2, h);
-  EXPECT_NE(h2, nullptr);
+  EXPECT_EQ(h2, h);
 
-  // But it still points to the same file.
+  // And still points to the same file.
   std::string contents = ReadFromFile(h);
   EXPECT_EQ(contents, std::string(kDataBuffer));
 
@@ -372,7 +384,7 @@
 
 // Similar to SendHandle, but sends a message with two instances of the same
 // handle.
-TEST_F(IPCAttachmentBrokerPrivilegedWinTest, DISABLED_SendTwoHandles) {
+TEST_F(IPCAttachmentBrokerPrivilegedWinTest, SendTwoHandles) {
   Init("SendTwoHandles");
 
   CommonSetUp();
@@ -380,8 +392,12 @@
   get_proxy_listener()->set_listener(&result_listener);
 
   HANDLE h = CreateTempFile();
+  HANDLE h2;
+  BOOL result = ::DuplicateHandle(GetCurrentProcess(), h, GetCurrentProcess(),
+                                  &h2, 0, FALSE, DUPLICATE_SAME_ACCESS);
+  ASSERT_TRUE(result);
   IPC::HandleWin handle_win1(h, IPC::HandleWin::FILE_READ_WRITE);
-  IPC::HandleWin handle_win2(h, IPC::HandleWin::FILE_READ_WRITE);
+  IPC::HandleWin handle_win2(h2, IPC::HandleWin::FILE_READ_WRITE);
   IPC::Message* message = new TestTwoHandleWinMsg(handle_win1, handle_win2);
   sender()->Send(message);
   base::MessageLoop::current()->Run();
@@ -395,7 +411,7 @@
 }
 
 // Similar to SendHandle, but sends the same message twice.
-TEST_F(IPCAttachmentBrokerPrivilegedWinTest, DISABLED_SendHandleTwice) {
+TEST_F(IPCAttachmentBrokerPrivilegedWinTest, SendHandleTwice) {
   Init("SendHandleTwice");
 
   CommonSetUp();
@@ -403,8 +419,12 @@
   get_proxy_listener()->set_listener(&result_listener);
 
   HANDLE h = CreateTempFile();
+  HANDLE h2;
+  BOOL result = ::DuplicateHandle(GetCurrentProcess(), h, GetCurrentProcess(),
+                                  &h2, 0, FALSE, DUPLICATE_SAME_ACCESS);
+  ASSERT_TRUE(result);
   SendMessageWithAttachment(h);
-  SendMessageWithAttachment(h);
+  SendMessageWithAttachment(h2);
   base::MessageLoop::current()->Run();
 
   // Check the result.
diff --git a/ipc/attachment_broker_unprivileged_win.cc b/ipc/attachment_broker_unprivileged_win.cc
index 9e9e7b21..9e01d89f 100644
--- a/ipc/attachment_broker_unprivileged_win.cc
+++ b/ipc/attachment_broker_unprivileged_win.cc
@@ -21,12 +21,15 @@
     base::ProcessId destination_process) {
   switch (attachment->GetBrokerableType()) {
     case BrokerableAttachment::WIN_HANDLE: {
-      const internal::HandleAttachmentWin* handle_attachment =
-          static_cast<const internal::HandleAttachmentWin*>(attachment.get());
+      internal::HandleAttachmentWin* handle_attachment =
+          static_cast<internal::HandleAttachmentWin*>(attachment.get());
       internal::HandleAttachmentWin::WireFormat format =
           handle_attachment->GetWireFormat(destination_process);
-      return get_sender()->Send(
+      bool success = get_sender()->Send(
           new AttachmentBrokerMsg_DuplicateWinHandle(format));
+      if (success)
+        handle_attachment->reset_handle_ownership();
+      return success;
     }
     case BrokerableAttachment::MACH_PORT:
     case BrokerableAttachment::PLACEHOLDER:
diff --git a/ipc/handle_attachment_win.cc b/ipc/handle_attachment_win.cc
index c14adcb8..5afd7fa 100644
--- a/ipc/handle_attachment_win.cc
+++ b/ipc/handle_attachment_win.cc
@@ -11,20 +11,22 @@
 
 HandleAttachmentWin::HandleAttachmentWin(const HANDLE& handle,
                                          HandleWin::Permissions permissions)
-    : handle_(handle), permissions_(permissions) {}
+    : handle_(handle), permissions_(permissions), owns_handle_(true) {}
 
 HandleAttachmentWin::HandleAttachmentWin(const WireFormat& wire_format)
     : BrokerableAttachment(wire_format.attachment_id),
       handle_(LongToHandle(wire_format.handle)),
-      permissions_(wire_format.permissions) {}
+      permissions_(wire_format.permissions), owns_handle_(false) {}
 
 HandleAttachmentWin::HandleAttachmentWin(
     const BrokerableAttachment::AttachmentId& id)
     : BrokerableAttachment(id),
       handle_(INVALID_HANDLE_VALUE),
-      permissions_(HandleWin::INVALID) {}
+      permissions_(HandleWin::INVALID), owns_handle_(false) {}
 
 HandleAttachmentWin::~HandleAttachmentWin() {
+  if (handle_ != INVALID_HANDLE_VALUE && owns_handle_)
+    ::CloseHandle(handle_);
 }
 
 HandleAttachmentWin::BrokerableType HandleAttachmentWin::GetBrokerableType()
diff --git a/ipc/handle_attachment_win.h b/ipc/handle_attachment_win.h
index 0888085..35807b4 100644
--- a/ipc/handle_attachment_win.h
+++ b/ipc/handle_attachment_win.h
@@ -41,7 +41,7 @@
     // The type is int32_t instead of HANDLE because HANDLE gets typedefed to
     // void*, whose size varies between 32 and 64-bit processes. Using a
     // int32_t means that 64-bit processes will need to perform both up-casting
-    // and down-casting. This is performed using the appropriate Windows apis.
+    // and down-casting. This is performed using the appropriate Windows APIs.
     // A value of 0 is equivalent to an invalid handle.
     int32_t handle;
 
@@ -54,7 +54,12 @@
     AttachmentId attachment_id;
   };
 
+  // This constructor makes a copy of |handle| and takes ownership of the
+  // result. Should only be called by the sender of a Chrome IPC message.
   HandleAttachmentWin(const HANDLE& handle, HandleWin::Permissions permissions);
+
+  // These constructors do not take ownership of the HANDLE, and should only be
+  // called by the receiver of a Chrome IPC message.
   explicit HandleAttachmentWin(const WireFormat& wire_format);
   explicit HandleAttachmentWin(const BrokerableAttachment::AttachmentId& id);
 
@@ -65,10 +70,21 @@
 
   HANDLE get_handle() const { return handle_; }
 
+  // The caller of this method has taken ownership of |handle_|.
+  void reset_handle_ownership() { owns_handle_ = false; }
+
  private:
   ~HandleAttachmentWin() override;
   HANDLE handle_;
   HandleWin::Permissions permissions_;
+
+  // In the sender process, the attachment owns the HANDLE of a newly created
+  // message. The attachment broker will eventually take ownership, and set
+  // this member to |false|.
+  // In the destination process, the attachment never owns the Mach port. The
+  // client code that receives the Chrome IPC message is always expected to take
+  // ownership.
+  bool owns_handle_;
 };
 
 }  // namespace internal
diff --git a/ipc/handle_win.cc b/ipc/handle_win.cc
index 7032114..45fbae4 100644
--- a/ipc/handle_win.cc
+++ b/ipc/handle_win.cc
@@ -4,6 +4,8 @@
 
 #include "ipc/handle_win.h"
 
+#include <utility>
+
 #include "base/logging.h"
 #include "base/memory/ref_counted.h"
 #include "base/strings/string_number_conversions.h"
@@ -23,7 +25,7 @@
   scoped_refptr<IPC::internal::HandleAttachmentWin> attachment(
       new IPC::internal::HandleAttachmentWin(p.get_handle(),
                                              p.get_permissions()));
-  if (!m->WriteAttachment(attachment.Pass()))
+  if (!m->WriteAttachment(std::move(attachment)))
     NOTREACHED();
 }
 
diff --git a/ipc/handle_win.h b/ipc/handle_win.h
index 8c640f7..38cddae 100644
--- a/ipc/handle_win.h
+++ b/ipc/handle_win.h
@@ -23,6 +23,10 @@
 // HandleWin is a wrapper around a Windows HANDLE that can be transported
 // across Chrome IPC channels that support attachment brokering. The HANDLE will
 // be duplicated into the destination process.
+//
+// The ownership semantics for the underlying |handle_| are complex. See
+// ipc/mach_port_mac.h (the OSX analog of this class) for an extensive
+// discussion.
 class IPC_EXPORT HandleWin {
  public:
   enum Permissions {
diff --git a/ipc/ipc_channel_reader_unittest.cc b/ipc/ipc_channel_reader_unittest.cc
index ee29072c8..b83f08cd 100644
--- a/ipc/ipc_channel_reader_unittest.cc
+++ b/ipc/ipc_channel_reader_unittest.cc
@@ -16,7 +16,7 @@
 
 // Whether IPC::Message::FindNext() can determine message size for
 // partial messages. The condition is from FindNext() implementation.
-#if USE_ATTACHMENT_BROKER && defined(OS_MACOSX) && !defined(OS_IOS)
+#if USE_ATTACHMENT_BROKER
 #define MESSAGE_FINDNEXT_PARTIAL 0
 #else
 #define MESSAGE_FINDNEXT_PARTIAL 1
diff --git a/ipc/ipc_message.cc b/ipc/ipc_message.cc
index d64c8028..d51cb65 100644
--- a/ipc/ipc_message.cc
+++ b/ipc/ipc_message.cc
@@ -50,7 +50,7 @@
 Message::Message() : base::Pickle(sizeof(Header)) {
   header()->routing = header()->type = 0;
   header()->flags = GetRefNumUpper24();
-#if defined(OS_MACOSX)
+#if USE_ATTACHMENT_BROKER
   header()->num_brokered_attachments = 0;
 #endif
 #if defined(OS_POSIX)
@@ -66,7 +66,7 @@
   header()->type = type;
   DCHECK((priority & 0xffffff00) == 0);
   header()->flags = priority | GetRefNumUpper24();
-#if defined(OS_MACOSX)
+#if USE_ATTACHMENT_BROKER
   header()->num_brokered_attachments = 0;
 #endif
 #if defined(OS_POSIX)
@@ -180,7 +180,7 @@
   bool have_entire_pickle =
       static_cast<size_t>(range_end - range_start) >= pickle_size;
 
-#if USE_ATTACHMENT_BROKER && defined(OS_MACOSX) && !defined(OS_IOS)
+#if USE_ATTACHMENT_BROKER
   // TODO(dskiba): determine message_size when entire pickle is not available
 
   if (!have_entire_pickle)
@@ -252,7 +252,7 @@
   // keep the current descriptor as extra decoding state when deserialising.
   WriteInt(static_cast<int>(index));
 
-#if USE_ATTACHMENT_BROKER && defined(OS_MACOSX) && !defined(OS_IOS)
+#if USE_ATTACHMENT_BROKER
   if (brokerable)
     header()->num_brokered_attachments++;
 #endif
diff --git a/ipc/ipc_message.h b/ipc/ipc_message.h
index 22d1c99..cace8d37 100644
--- a/ipc/ipc_message.h
+++ b/ipc/ipc_message.h
@@ -13,6 +13,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/pickle.h"
 #include "base/trace_event/trace_event.h"
+#include "ipc/attachment_broker.h"
 #include "ipc/brokerable_attachment.h"
 #include "ipc/ipc_export.h"
 
@@ -268,7 +269,7 @@
     int32_t routing;  // ID of the view that this message is destined for
     uint32_t type;    // specifies the user-defined message type
     uint32_t flags;   // specifies control flags for the message
-#if defined(OS_MACOSX)
+#if USE_ATTACHMENT_BROKER
     // The number of brokered attachments included with this message. The
     // ids of the brokered attachment ids are sent immediately after the pickled
     // message, before the next pickled message is sent.
diff --git a/ipc/ipc_message_unittest.cc b/ipc/ipc_message_unittest.cc
index bb133e57..1bd4df3 100644
--- a/ipc/ipc_message_unittest.cc
+++ b/ipc/ipc_message_unittest.cc
@@ -149,7 +149,7 @@
   // (but contains the message header)
   IPC::Message::FindNext(data_start, data_end - 1, &next);
   EXPECT_FALSE(next.message_found);
-#if USE_ATTACHMENT_BROKER && defined(OS_MACOSX) && !defined(OS_IOS)
+#if USE_ATTACHMENT_BROKER
   EXPECT_EQ(next.message_size, 0u);
 #else
   EXPECT_EQ(next.message_size, message.size());
@@ -185,7 +185,7 @@
   message.header()->payload_size = static_cast<uint32_t>(-1);
   IPC::Message::FindNext(data_start, data_end, &next);
   EXPECT_FALSE(next.message_found);
-#if USE_ATTACHMENT_BROKER && defined(OS_MACOSX) && !defined(OS_IOS)
+#if USE_ATTACHMENT_BROKER
   EXPECT_EQ(next.message_size, 0u);
 #else
   if (sizeof(size_t) > sizeof(uint32_t)) {
@@ -203,7 +203,7 @@
   message.header()->payload_size = std::numeric_limits<int32_t>::max();
   IPC::Message::FindNext(data_start, data_end, &next);
   EXPECT_FALSE(next.message_found);
-#if USE_ATTACHMENT_BROKER && defined(OS_MACOSX) && !defined(OS_IOS)
+#if USE_ATTACHMENT_BROKER
   EXPECT_EQ(next.message_size, 0u);
 #else
   EXPECT_EQ(next.message_size,
diff --git a/mandoline/app/android/BUILD.gn b/mandoline/app/android/BUILD.gn
index 59bbcb4..e5e50b0b 100644
--- a/mandoline/app/android/BUILD.gn
+++ b/mandoline/app/android/BUILD.gn
@@ -6,9 +6,6 @@
 
 import("//build/config/android/config.gni")
 import("//build/config/android/rules.gni")
-import("//mojo/generate_mojo_shell_assets_list.gni")
-
-mandoline_assets_dir = "$root_build_dir/mandoline_assets"
 
 group("android") {
   deps = [
@@ -54,49 +51,24 @@
   ]
 }
 
-copy_ex("copy_mandoline_assets") {
-  clear_dir = true
-  dest = mandoline_assets_dir
+android_assets("mandoline_assets") {
   deps = [
-    "//components/devtools_service",
-    "//components/html_viewer",
-    "//components/resource_provider",
-    "//mandoline/services/core_services",
-    "//mojo/runner:bootstrap",
-    "//mojo/runner:bootstrap_java",
-    "//mojo/services/network",
-  ]
-  sources = [
-    "$root_out_dir/obj/mojo/runner/bootstrap_java.dex.jar",
-    "$root_shlib_dir/${shlib_prefix}bootstrap$shlib_extension",
-  ]
-
-  # Directories can't be specified as sources so pass manually to the script.
-  args = [
-    "--files=" + rebase_path("$root_out_dir/core_services", root_build_dir),
-    "--files=" + rebase_path("$root_out_dir/network_service", root_build_dir),
-    "--files=" + rebase_path("$root_out_dir/resource_provider", root_build_dir),
-    "--files=" + rebase_path("$root_out_dir/devtools_service", root_build_dir),
-    "--files=" + rebase_path("$root_out_dir/html_viewer", root_build_dir),
+    "//components/devtools_service:devtools_service_assets",
+    "//components/html_viewer:html_viewer_assets",
+    "//components/resource_provider:resource_provider_assets",
+    "//mandoline/services/core_services:core_services_assets",
+    "//mojo/runner:android_assets",
+    "//mojo/services/network:network_assets",
   ]
 
   if (use_aura) {
-    deps += [ "//mandoline/ui" ]
-
-    args += [
-      "--files=" + rebase_path("$root_out_dir/omnibox", root_build_dir),
-      "--files=" + rebase_path("$root_out_dir/phone_ui", root_build_dir),
+    deps += [
+      "//mandoline/ui/desktop_ui:desktop_ui_assets",
+      "//mandoline/ui/omnibox:omnibox_assets",
     ]
   }
 }
 
-generate_mojo_shell_assets_list("build_mandoline_assets") {
-  deps = [
-    ":copy_mandoline_assets",
-  ]
-  dir = mandoline_assets_dir
-}
-
 android_library("java") {
   java_files = [ "apk/src/org/chromium/mandoline/MandolineActivity.java" ]
 
@@ -122,16 +94,14 @@
   apk_name = "Mandoline"
 
   android_manifest = "apk/AndroidManifest.xml"
-
   native_libs = [ "${shlib_prefix}mandoline_runner$shlib_extension" ]
-
-  asset_location = mandoline_assets_dir
+  write_asset_list = true
 
   deps = [
-    ":build_mandoline_assets",
     ":copy_mandoline_runner",
     ":java",
     ":mandoline_apk_resources",
+    ":mandoline_assets",
     "//base:base_java",
     "//mojo/runner:java",
     "//mojo/runner:resources",
diff --git a/mash/BUILD.gn b/mash/BUILD.gn
index 060bdc6..461ff4c 100644
--- a/mash/BUILD.gn
+++ b/mash/BUILD.gn
@@ -9,8 +9,16 @@
   testonly = true
 
   deps = [
-    ":mash_unittests",
+    ":tests",
     "//mash/example",
+  ]
+}
+
+group("tests") {
+  testonly = true
+
+  deps = [
+    ":mash_unittests",
     "//mash/wm:tests",
   ]
 }
diff --git a/mash/browser_driver/BUILD.gn b/mash/browser_driver/BUILD.gn
new file mode 100644
index 0000000..a585925
--- /dev/null
+++ b/mash/browser_driver/BUILD.gn
@@ -0,0 +1,25 @@
+# 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.
+
+import("//build/config/ui.gni")
+import("//mojo/public/mojo_application.gni")
+import("//mojo/public/tools/bindings/mojom.gni")
+import("//tools/grit/repack.gni")
+
+mojo_native_application("browser_driver") {
+  sources = [
+    "browser_driver_application_delegate.cc",
+    "browser_driver_application_delegate.h",
+    "main.cc",
+  ]
+
+  deps = [
+    "//base",
+    "//components/mus/public/cpp",
+    "//components/mus/public/interfaces",
+    "//mojo/application/public/cpp",
+    "//mojo/application/public/cpp:sources",
+    "//mojo/public/cpp/bindings",
+  ]
+}
diff --git a/mash/browser_driver/browser_driver_application_delegate.cc b/mash/browser_driver/browser_driver_application_delegate.cc
new file mode 100644
index 0000000..b5d95f50
--- /dev/null
+++ b/mash/browser_driver/browser_driver_application_delegate.cc
@@ -0,0 +1,103 @@
+// 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.
+
+#include "mash/browser_driver/browser_driver_application_delegate.h"
+
+#include "base/bind.h"
+#include "components/mus/public/cpp/event_matcher.h"
+#include "mojo/application/public/cpp/application_connection.h"
+#include "mojo/application/public/cpp/application_impl.h"
+
+namespace mash {
+namespace browser_driver {
+namespace {
+
+enum class Accelerator : uint32_t {
+  NewWindow,
+  NewTab,
+  NewIncognitoWindow,
+};
+
+struct AcceleratorSpec {
+  Accelerator id;
+  mus::mojom::KeyboardCode keyboard_code;
+  mus::mojom::EventFlags event_flags;
+};
+
+AcceleratorSpec g_spec[] = {
+  { Accelerator::NewWindow,
+    mus::mojom::KEYBOARD_CODE_N,
+    mus::mojom::EVENT_FLAGS_CONTROL_DOWN },
+  { Accelerator::NewTab,
+    mus::mojom::KEYBOARD_CODE_T,
+    mus::mojom::EVENT_FLAGS_CONTROL_DOWN },
+  { Accelerator::NewIncognitoWindow,
+    mus::mojom::KEYBOARD_CODE_N,
+    static_cast<mus::mojom::EventFlags>(mus::mojom::EVENT_FLAGS_CONTROL_DOWN |
+        mus::mojom::EVENT_FLAGS_SHIFT_DOWN) },
+};
+
+void AssertTrue(bool success) {
+  DCHECK(success);
+}
+
+}  // namespace
+
+BrowserDriverApplicationDelegate::BrowserDriverApplicationDelegate()
+    : app_(nullptr),
+      binding_(this) {}
+
+BrowserDriverApplicationDelegate::~BrowserDriverApplicationDelegate() {}
+
+void BrowserDriverApplicationDelegate::Initialize(mojo::ApplicationImpl* app) {
+  app_ = app;
+  AddAccelerators();
+}
+
+bool BrowserDriverApplicationDelegate::ConfigureIncomingConnection(
+    mojo::ApplicationConnection* connection) {
+  return false;
+}
+
+void BrowserDriverApplicationDelegate::OnAccelerator(
+    uint32_t id, mus::mojom::EventPtr event) {
+  switch (static_cast<Accelerator>(id)) {
+    case Accelerator::NewWindow:
+    case Accelerator::NewTab:
+    case Accelerator::NewIncognitoWindow:
+      app_->ConnectToApplication("exe:chrome");
+      // TODO(beng): have Chrome export a service that allows it to be driven by
+      //             this driver, e.g. to open new tabs, incognito windows, etc.
+      break;
+    default:
+      NOTREACHED();
+      break;
+  }
+}
+
+void BrowserDriverApplicationDelegate::AddAccelerators() {
+  // TODO(beng): find some other way to get the window manager. I don't like
+  //             having to specify it by URL because it may differ per display.
+  mus::mojom::AcceleratorRegistrarPtr registrar;
+  app_->ConnectToService("mojo:desktop_wm", &registrar);
+
+  mus::mojom::AcceleratorHandlerPtr handler;
+  binding_.Bind(GetProxy(&handler));
+  // If the window manager restarts, the handler pipe will close and we'll need
+  // to re-add our accelerators when the window manager comes back up.
+  binding_.set_connection_error_handler(
+      base::Bind(&BrowserDriverApplicationDelegate::AddAccelerators,
+                 base::Unretained(this)));
+  registrar->SetHandler(std::move(handler));
+
+  for (const AcceleratorSpec& spec : g_spec) {
+    registrar->AddAccelerator(
+        static_cast<uint32_t>(spec.id),
+        mus::CreateKeyMatcher(spec.keyboard_code, spec.event_flags),
+        base::Bind(&AssertTrue));
+  }
+}
+
+}  // namespace browser_driver
+}  // namespace main
diff --git a/mash/browser_driver/browser_driver_application_delegate.h b/mash/browser_driver/browser_driver_application_delegate.h
new file mode 100644
index 0000000..df2a4b61
--- /dev/null
+++ b/mash/browser_driver/browser_driver_application_delegate.h
@@ -0,0 +1,50 @@
+// 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.
+
+#ifndef MASH_BROWSER_DRIVER_BROWSER_DRIVER_APPLICATION_DELEGATE_H_
+#define MASH_BROWSER_DRIVER_BROWSER_DRIVER_APPLICATION_DELEGATE_H_
+
+#include <map>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "components/mus/public/interfaces/accelerator_registrar.mojom.h"
+#include "mojo/application/public/cpp/application_delegate.h"
+#include "mojo/public/cpp/bindings/binding.h"
+
+namespace mojo {
+class ApplicationConnection;
+}
+
+namespace mash {
+namespace browser_driver {
+
+class BrowserDriverApplicationDelegate : public mojo::ApplicationDelegate,
+                                         public mus::mojom::AcceleratorHandler {
+ public:
+  BrowserDriverApplicationDelegate();
+  ~BrowserDriverApplicationDelegate() override;
+
+ private:
+  // mojo::ApplicationDelegate:
+  void Initialize(mojo::ApplicationImpl* app) override;
+  bool ConfigureIncomingConnection(
+      mojo::ApplicationConnection* connection) override;
+
+  // mus::mojom::AcceleratorHandler:
+  void OnAccelerator(uint32_t id, mus::mojom::EventPtr event) override;
+
+  void AddAccelerators();
+
+  mojo::ApplicationImpl* app_;
+  mojo::Binding<mus::mojom::AcceleratorHandler> binding_;
+
+  DISALLOW_COPY_AND_ASSIGN(BrowserDriverApplicationDelegate);
+};
+
+}  // namespace browser_driver
+}  // namespace mash
+
+#endif  // MASH_BROWSER_DRIVER_BROWSER_DRIVER_APPLICATION_DELEGATE_H_
diff --git a/mash/browser_driver/main.cc b/mash/browser_driver/main.cc
new file mode 100644
index 0000000..514178cd
--- /dev/null
+++ b/mash/browser_driver/main.cc
@@ -0,0 +1,13 @@
+// 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.
+
+#include "mash/browser_driver/browser_driver_application_delegate.h"
+#include "mojo/application/public/cpp/application_runner.h"
+#include "mojo/public/c/system/main.h"
+
+MojoResult MojoMain(MojoHandle shell_handle) {
+  mojo::ApplicationRunner runner(
+      new mash::browser_driver::BrowserDriverApplicationDelegate);
+  return runner.Run(shell_handle);
+}
diff --git a/mash/example/main/main_application_delegate.cc b/mash/example/main/main_application_delegate.cc
index 3fc15ce4..da992b7 100644
--- a/mash/example/main/main_application_delegate.cc
+++ b/mash/example/main/main_application_delegate.cc
@@ -16,7 +16,6 @@
   connections_.push_back(app->ConnectToApplication("mojo:views_examples"));
   connections_.push_back(
       app->ConnectToApplication("exe:window_type_launcher_exe"));
-  connections_.push_back(app->ConnectToApplication("exe:chrome"));
 }
 
 bool MainApplicationDelegate::ConfigureIncomingConnection(
diff --git a/mash/shell/BUILD.gn b/mash/shell/BUILD.gn
index d1ef272..6e629ba 100644
--- a/mash/shell/BUILD.gn
+++ b/mash/shell/BUILD.gn
@@ -24,6 +24,7 @@
   ]
 
   data_deps = [
+    "//mash/browser_driver",
     "//mash/system_ui",
     "//mash/wm",
   ]
diff --git a/mash/shell/shell_application_delegate.cc b/mash/shell/shell_application_delegate.cc
index 702adc4a..a958446 100644
--- a/mash/shell/shell_application_delegate.cc
+++ b/mash/shell/shell_application_delegate.cc
@@ -17,6 +17,7 @@
 
 void ShellApplicationDelegate::Initialize(mojo::ApplicationImpl* app) {
   app_ = app;
+  StartBrowserDriver();
   StartWindowManager();
   StartSystemUI();
 }
@@ -39,6 +40,13 @@
                                      base::Unretained(this)));
 }
 
+void ShellApplicationDelegate::StartBrowserDriver() {
+  StartRestartableService(
+      "mojo:browser_driver",
+      base::Bind(&ShellApplicationDelegate::StartBrowserDriver,
+                 base::Unretained(this)));
+}
+
 void ShellApplicationDelegate::StartRestartableService(
     const std::string& url,
     const base::Closure& restart_callback) {
diff --git a/mash/shell/shell_application_delegate.h b/mash/shell/shell_application_delegate.h
index 471f4a1..3bec26c 100644
--- a/mash/shell/shell_application_delegate.h
+++ b/mash/shell/shell_application_delegate.h
@@ -32,6 +32,7 @@
 
   void StartWindowManager();
   void StartSystemUI();
+  void StartBrowserDriver();
 
   // Starts the application at |url|, running |restart_callback| if the
   // connection to the application is closed.
diff --git a/mash/wm/BUILD.gn b/mash/wm/BUILD.gn
index 743307d..83e4296 100644
--- a/mash/wm/BUILD.gn
+++ b/mash/wm/BUILD.gn
@@ -46,6 +46,8 @@
     "property_util.h",
     "shadow.cc",
     "shadow.h",
+    "shadow_controller.cc",
+    "shadow_controller.h",
     "shelf_layout.cc",
     "shelf_layout.h",
     "window_layout.cc",
diff --git a/mash/wm/frame/non_client_frame_view_mash.cc b/mash/wm/frame/non_client_frame_view_mash.cc
index 17af114e3..76cb630a 100644
--- a/mash/wm/frame/non_client_frame_view_mash.cc
+++ b/mash/wm/frame/non_client_frame_view_mash.cc
@@ -292,7 +292,12 @@
 
 void NonClientFrameViewMash::OnWindowClientAreaChanged(
     mus::Window* window,
-    const gfx::Insets& old_client_area) {
+    const gfx::Insets& old_client_area,
+    const std::vector<gfx::Rect>& old_additional_client_area) {
+  // Only the insets effect the rendering.
+  if (old_client_area == window->client_area())
+    return;
+
   Layout();
   // NonClientView (our parent) positions the client view based on bounds from
   // us. We need to layout from parent to trigger a layout of the client view.
diff --git a/mash/wm/frame/non_client_frame_view_mash.h b/mash/wm/frame/non_client_frame_view_mash.h
index f87ef2e6..e39f44d 100644
--- a/mash/wm/frame/non_client_frame_view_mash.h
+++ b/mash/wm/frame/non_client_frame_view_mash.h
@@ -66,8 +66,10 @@
   void PaintChildren(const ui::PaintContext& context) override;
 
   // mus::WindowObserver:
-  void OnWindowClientAreaChanged(mus::Window* window,
-                                 const gfx::Insets& old_client_area) override;
+  void OnWindowClientAreaChanged(
+      mus::Window* window,
+      const gfx::Insets& old_client_area,
+      const std::vector<gfx::Rect>& old_additional_client_area) override;
   void OnWindowDestroyed(mus::Window* window) override;
 
   // Get the view of the header.
diff --git a/mash/wm/non_client_frame_controller.cc b/mash/wm/non_client_frame_controller.cc
index 4cd4027..ca8e9a63 100644
--- a/mash/wm/non_client_frame_controller.cc
+++ b/mash/wm/non_client_frame_controller.cc
@@ -117,7 +117,8 @@
     aura::WindowTreeHost* window_tree_host = GetNativeView()->GetHost();
     // TODO(sky): shadow should be determined by window type.
     shadow_.reset(new Shadow);
-    shadow_->Init(Shadow::STYLE_ACTIVE);
+    shadow_->Init(Shadow::STYLE_INACTIVE);
+    SetShadow(window(), shadow_.get());
     ContentWindowLayoutManager* layout_manager = new ContentWindowLayoutManager(
         window_tree_host->window(), ShadowStyle::NORMAL, shadow_.get());
     window_tree_host->window()->SetLayoutManager(layout_manager);
diff --git a/mash/wm/property_util.cc b/mash/wm/property_util.cc
index f08cf7a5..6295cd00 100644
--- a/mash/wm/property_util.cc
+++ b/mash/wm/property_util.cc
@@ -7,11 +7,17 @@
 #include "components/mus/public/cpp/property_type_converters.h"
 #include "components/mus/public/cpp/window.h"
 #include "components/mus/public/cpp/window_property.h"
+#include "mash/wm/shadow.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/geometry/size.h"
 
 namespace mash {
 namespace wm {
+namespace {
+
+DEFINE_LOCAL_WINDOW_PROPERTY_KEY(Shadow*, kLocalShadowProperty, nullptr);
+
+}  // namespace
 
 mus::mojom::ShowState GetWindowShowState(const mus::Window* window) {
   if (window->HasSharedProperty(
@@ -88,5 +94,13 @@
   return gfx::Rect();
 }
 
+void SetShadow(mus::Window* window, Shadow* shadow) {
+  window->SetLocalProperty(kLocalShadowProperty, shadow);
+}
+
+Shadow* GetShadow(mus::Window* window) {
+  return window->GetLocalProperty(kLocalShadowProperty);
+}
+
 }  // namespace wm
 }  // namespace mash
diff --git a/mash/wm/property_util.h b/mash/wm/property_util.h
index 104e870..4e7616b 100644
--- a/mash/wm/property_util.h
+++ b/mash/wm/property_util.h
@@ -21,6 +21,8 @@
 namespace mash {
 namespace wm {
 
+class Shadow;
+
 // Utility functions to read values from properties & convert them to the
 // appropriate types.
 
@@ -39,6 +41,9 @@
 void SetRestoreBounds(mus::Window* window, const gfx::Rect& bounds);
 gfx::Rect GetRestoreBounds(const mus::Window* window);
 
+void SetShadow(mus::Window* window, Shadow* shadow);
+Shadow* GetShadow(mus::Window* window);
+
 }  // namespace wm
 }  // namespace mash
 
diff --git a/mash/wm/shadow_controller.cc b/mash/wm/shadow_controller.cc
new file mode 100644
index 0000000..b7f91f1
--- /dev/null
+++ b/mash/wm/shadow_controller.cc
@@ -0,0 +1,66 @@
+// 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.
+
+#include "mash/wm/shadow_controller.h"
+
+#include "components/mus/public/cpp/window.h"
+#include "components/mus/public/cpp/window_tree_connection.h"
+#include "mash/wm/property_util.h"
+#include "mash/wm/shadow.h"
+
+namespace mash {
+namespace wm {
+namespace {
+
+// Returns the first ancestor of |from| (including |from|) that has a shadow.
+mus::Window* FindAncestorWithShadow(mus::Window* from) {
+  mus::Window* result = from;
+  while (result && !GetShadow(result))
+    result = result->parent();
+  // Small shadows never change.
+  return result && GetShadow(result)->style() != Shadow::STYLE_SMALL ? result
+                                                                     : nullptr;
+}
+
+}  // namespace
+
+ShadowController::ShadowController(mus::WindowTreeConnection* window_tree)
+    : window_tree_(window_tree), active_window_(nullptr) {
+  window_tree_->AddObserver(this);
+  SetActiveWindow(FindAncestorWithShadow(window_tree_->GetFocusedWindow()));
+}
+
+ShadowController::~ShadowController() {
+  window_tree_->RemoveObserver(this);
+  if (active_window_)
+    active_window_->RemoveObserver(this);
+}
+
+void ShadowController::SetActiveWindow(mus::Window* window) {
+  if (window == active_window_)
+    return;
+
+  if (active_window_) {
+    GetShadow(active_window_)->SetStyle(Shadow::STYLE_INACTIVE);
+    active_window_->RemoveObserver(this);
+  }
+  active_window_ = window;
+  if (active_window_) {
+    GetShadow(active_window_)->SetStyle(Shadow::STYLE_ACTIVE);
+    active_window_->AddObserver(this);
+  }
+}
+
+void ShadowController::OnWindowTreeFocusChanged(mus::Window* gained_focus,
+                                                mus::Window* lost_focus) {
+  SetActiveWindow(FindAncestorWithShadow(gained_focus));
+}
+
+void ShadowController::OnWindowDestroying(mus::Window* window) {
+  DCHECK_EQ(window, active_window_);
+  SetActiveWindow(nullptr);
+}
+
+}  // namespace wm
+}  // namespace mash
diff --git a/mash/wm/shadow_controller.h b/mash/wm/shadow_controller.h
new file mode 100644
index 0000000..cc11f4f
--- /dev/null
+++ b/mash/wm/shadow_controller.h
@@ -0,0 +1,44 @@
+// 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.
+
+#ifndef MASH_WM_SHADOW_CONTROLLER_H_
+#define MASH_WM_SHADOW_CONTROLLER_H_
+
+#include "base/basictypes.h"
+#include "components/mus/public/cpp/window_observer.h"
+#include "components/mus/public/cpp/window_tree_connection_observer.h"
+
+namespace mus {
+class WindowTreeConnection;
+}
+
+namespace mash {
+namespace wm {
+
+class ShadowController : public mus::WindowTreeConnectionObserver,
+                         public mus::WindowObserver {
+ public:
+  explicit ShadowController(mus::WindowTreeConnection* window_tree);
+  ~ShadowController() override;
+
+ private:
+  void SetActiveWindow(mus::Window* window);
+
+  // mus::WindowTreeConnectionObserver:
+  void OnWindowTreeFocusChanged(mus::Window* gained_focus,
+                                mus::Window* lost_focus) override;
+
+  // mus::WindowObserver:
+  void OnWindowDestroying(mus::Window* window) override;
+
+  mus::WindowTreeConnection* window_tree_;
+  mus::Window* active_window_;
+
+  DISALLOW_COPY_AND_ASSIGN(ShadowController);
+};
+
+}  // namespace wm
+}  // namespace mash
+
+#endif  // MASH_WM_SHADOW_CONTROLLER_H_
diff --git a/mash/wm/window_manager_application.cc b/mash/wm/window_manager_application.cc
index 3a211d5..ad0d4c6 100644
--- a/mash/wm/window_manager_application.cc
+++ b/mash/wm/window_manager_application.cc
@@ -12,6 +12,7 @@
 #include "components/mus/public/cpp/window_tree_host_factory.h"
 #include "mash/wm/accelerator_registrar_impl.h"
 #include "mash/wm/background_layout.h"
+#include "mash/wm/shadow_controller.h"
 #include "mash/wm/shelf_layout.h"
 #include "mash/wm/window_layout.h"
 #include "mash/wm/window_manager_impl.h"
@@ -130,12 +131,15 @@
   for (auto request : requests_)
     window_manager_binding_.AddBinding(window_manager_.get(), request->Pass());
   requests_.clear();
+
+  shadow_controller_.reset(new ShadowController(root->connection()));
 }
 
 void WindowManagerApplication::OnConnectionLost(
     mus::WindowTreeConnection* connection) {
   // TODO(sky): shutdown.
   NOTIMPLEMENTED();
+  shadow_controller_.reset();
 }
 
 void WindowManagerApplication::Create(
diff --git a/mash/wm/window_manager_application.h b/mash/wm/window_manager_application.h
index 45916ea..7253d22 100644
--- a/mash/wm/window_manager_application.h
+++ b/mash/wm/window_manager_application.h
@@ -37,6 +37,7 @@
 
 class AcceleratorRegistrarImpl;
 class BackgroundLayout;
+class ShadowController;
 class ShelfLayout;
 class WindowLayout;
 class WindowManagerImpl;
@@ -123,6 +124,8 @@
   scoped_ptr<ShelfLayout> shelf_layout_;
   scoped_ptr<WindowLayout> window_layout_;
 
+  scoped_ptr<ShadowController> shadow_controller_;
+
   std::set<AcceleratorRegistrarImpl*> accelerator_registrars_;
 
   DISALLOW_COPY_AND_ASSIGN(WindowManagerApplication);
diff --git a/mash/wm/window_manager_apptest.cc b/mash/wm/window_manager_apptest.cc
index 5e235fc..079af7b 100644
--- a/mash/wm/window_manager_apptest.cc
+++ b/mash/wm/window_manager_apptest.cc
@@ -46,7 +46,8 @@
   DISALLOW_COPY_AND_ASSIGN(WindowManagerAppTest);
 };
 
-TEST_F(WindowManagerAppTest, OpenWindow) {
+// TODO(sky): flakey, http://crbug.com/559412 .
+TEST_F(WindowManagerAppTest, DISABLED_OpenWindow) {
   mus::mojom::WindowManagerPtr connection;
   ConnectToWindowManager(&connection);
 
diff --git a/media/audio/audio_device_thread.cc b/media/audio/audio_device_thread.cc
index 94472939..81dab87 100644
--- a/media/audio/audio_device_thread.cc
+++ b/media/audio/audio_device_thread.cc
@@ -4,7 +4,10 @@
 
 #include "media/audio/audio_device_thread.h"
 
+#include <stdint.h>
+
 #include <algorithm>
+#include <limits>
 
 #include "base/bind.h"
 #include "base/logging.h"
@@ -163,21 +166,22 @@
 }
 
 void AudioDeviceThread::Thread::Run() {
-  uint32 buffer_index = 0;
+  uint32_t buffer_index = 0;
   while (true) {
-    uint32 pending_data = 0;
+    uint32_t pending_data = 0;
     size_t bytes_read = socket_.Receive(&pending_data, sizeof(pending_data));
     if (bytes_read != sizeof(pending_data))
       break;
 
-    // kuint32max is a special signal which is returned after the browser
-    // stops the output device in response to a renderer side request.
+    // std::numeric_limits<uint32_t>::max() is a special signal which is
+    // returned after the browser stops the output device in response to a
+    // renderer side request.
     //
     // Avoid running Process() for the paused signal, we still need to update
     // the buffer index if |synchronized_buffers_| is true though.
     //
     // See comments in AudioOutputController::DoPause() for details on why.
-    if (pending_data != kuint32max) {
+    if (pending_data != std::numeric_limits<uint32_t>::max()) {
       base::AutoLock auto_lock(callback_lock_);
       if (callback_)
         callback_->Process(pending_data);
diff --git a/media/audio/audio_device_thread.h b/media/audio/audio_device_thread.h
index 1f63c21d..7e8e2bf 100644
--- a/media/audio/audio_device_thread.h
+++ b/media/audio/audio_device_thread.h
@@ -5,7 +5,7 @@
 #ifndef MEDIA_AUDIO_AUDIO_DEVICE_THREAD_H_
 #define MEDIA_AUDIO_AUDIO_DEVICE_THREAD_H_
 
-#include "base/basictypes.h"
+#include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/shared_memory.h"
diff --git a/media/audio/audio_output_controller.cc b/media/audio/audio_output_controller.cc
index 8aa2b4f..f092496 100644
--- a/media/audio/audio_output_controller.cc
+++ b/media/audio/audio_output_controller.cc
@@ -4,6 +4,10 @@
 
 #include "media/audio/audio_output_controller.h"
 
+#include <stdint.h>
+
+#include <limits>
+
 #include "base/bind.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/numerics/safe_conversions.h"
@@ -213,7 +217,7 @@
   // Let the renderer know we've stopped.  Necessary to let PPAPI clients know
   // audio has been shutdown.  TODO(dalecurtis): This stinks.  PPAPI should have
   // a better way to know when it should exit PPB_Audio_Shared::Run().
-  sync_reader_->UpdatePendingBytes(kuint32max);
+  sync_reader_->UpdatePendingBytes(std::numeric_limits<uint32_t>::max());
 
   handler_->OnPaused();
 }
@@ -280,7 +284,7 @@
 }
 
 int AudioOutputController::OnMoreData(AudioBus* dest,
-                                      uint32 total_bytes_delay) {
+                                      uint32_t total_bytes_delay) {
   TRACE_EVENT0("audio", "AudioOutputController::OnMoreData");
 
   // Indicate that we haven't wedged (at least not indefinitely, WedgeCheck()
@@ -293,7 +297,7 @@
   sync_reader_->Read(dest);
 
   const int frames = dest->frames();
-  sync_reader_->UpdatePendingBytes(base::saturated_cast<uint32>(
+  sync_reader_->UpdatePendingBytes(base::saturated_cast<uint32_t>(
       total_bytes_delay + frames * params_.GetBytesPerFrame()));
 
   if (will_monitor_audio_levels())
diff --git a/media/base/demuxer.h b/media/base/demuxer.h
index 2324c87..1f136a0c 100644
--- a/media/base/demuxer.h
+++ b/media/base/demuxer.h
@@ -87,8 +87,7 @@
   // a null Time is returned.
   virtual base::Time GetTimelineOffset() const = 0;
 
-  // Returns the memory usage in bytes for the demuxer. May be called from any
-  // thread.
+  // Returns the memory usage in bytes for the demuxer.
   virtual int64_t GetMemoryUsage() const = 0;
 
  private:
diff --git a/media/base/video_types.cc b/media/base/video_types.cc
index b6b041e..e2f137d 100644
--- a/media/base/video_types.cc
+++ b/media/base/video_types.cc
@@ -72,4 +72,28 @@
   return false;
 }
 
+bool IsOpaque(VideoPixelFormat format) {
+  switch (format) {
+    case PIXEL_FORMAT_UNKNOWN:
+    case PIXEL_FORMAT_I420:
+    case PIXEL_FORMAT_YV12:
+    case PIXEL_FORMAT_YV16:
+    case PIXEL_FORMAT_YV24:
+    case PIXEL_FORMAT_NV12:
+    case PIXEL_FORMAT_NV21:
+    case PIXEL_FORMAT_UYVY:
+    case PIXEL_FORMAT_YUY2:
+    case PIXEL_FORMAT_XRGB:
+    case PIXEL_FORMAT_RGB24:
+    case PIXEL_FORMAT_MJPEG:
+    case PIXEL_FORMAT_MT21:
+      return true;
+    case PIXEL_FORMAT_YV12A:
+    case PIXEL_FORMAT_ARGB:
+    case PIXEL_FORMAT_RGB32:
+      break;
+  }
+  return false;
+}
+
 }  // namespace media
diff --git a/media/base/video_types.h b/media/base/video_types.h
index b40dfb4..7cf196e6 100644
--- a/media/base/video_types.h
+++ b/media/base/video_types.h
@@ -69,6 +69,9 @@
 // Returns true if |format| is a YUV format with multiple planes.
 MEDIA_EXPORT bool IsYuvPlanar(VideoPixelFormat format);
 
+// Returns true if |format| has no Alpha channel (hence is always opaque).
+MEDIA_EXPORT bool IsOpaque(VideoPixelFormat format);
+
 }  // namespace media
 
 #endif  // MEDIA_BASE_VIDEO_TYPES_H_
diff --git a/media/blink/video_frame_compositor.cc b/media/blink/video_frame_compositor.cc
index 073ec97..4c43c505 100644
--- a/media/blink/video_frame_compositor.cc
+++ b/media/blink/video_frame_compositor.cc
@@ -16,31 +16,6 @@
 // background rendering to keep the Render() callbacks moving.
 const int kBackgroundRenderingTimeoutMs = 250;
 
-// Returns true if the format has no Alpha channel (hence is always opaque).
-static bool IsOpaque(const scoped_refptr<VideoFrame>& frame) {
-  switch (frame->format()) {
-    case PIXEL_FORMAT_UNKNOWN:
-    case PIXEL_FORMAT_I420:
-    case PIXEL_FORMAT_YV12:
-    case PIXEL_FORMAT_YV16:
-    case PIXEL_FORMAT_YV24:
-    case PIXEL_FORMAT_NV12:
-    case PIXEL_FORMAT_NV21:
-    case PIXEL_FORMAT_UYVY:
-    case PIXEL_FORMAT_YUY2:
-    case PIXEL_FORMAT_XRGB:
-    case PIXEL_FORMAT_RGB24:
-    case PIXEL_FORMAT_MJPEG:
-    case PIXEL_FORMAT_MT21:
-      return true;
-    case PIXEL_FORMAT_YV12A:
-    case PIXEL_FORMAT_ARGB:
-    case PIXEL_FORMAT_RGB32:
-      break;
-  }
-  return false;
-}
-
 VideoFrameCompositor::VideoFrameCompositor(
     const scoped_refptr<base::SingleThreadTaskRunner>& compositor_task_runner,
     const base::Callback<void(gfx::Size)>& natural_size_changed_cb,
@@ -213,8 +188,9 @@
     natural_size_changed_cb_.Run(frame->natural_size());
   }
 
-  if (!current_frame_ || IsOpaque(current_frame_) != IsOpaque(frame))
-    opacity_changed_cb_.Run(IsOpaque(frame));
+  if (!current_frame_ ||
+      IsOpaque(current_frame_->format()) != IsOpaque(frame->format()))
+    opacity_changed_cb_.Run(IsOpaque(frame->format()));
 
   current_frame_ = frame;
   return true;
diff --git a/media/capture/webm_muxer.cc b/media/capture/webm_muxer.cc
index 939cb397..3976c0f 100644
--- a/media/capture/webm_muxer.cc
+++ b/media/capture/webm_muxer.cc
@@ -19,7 +19,7 @@
   // See https://wiki.xiph.org/OggOpus#ID_Header.
   // Set magic signature.
   std::string label = "OpusHead";
-  memcpy(header + OPUS_EXTRADATA_LABEL_OFFSET, &label, label.size());
+  memcpy(header + OPUS_EXTRADATA_LABEL_OFFSET, label.c_str(), label.size());
   // Set Opus version.
   header[OPUS_EXTRADATA_VERSION_OFFSET] = 1;
   // Set channel count.
@@ -126,16 +126,20 @@
   // http://crbug.com/528523
   if (has_audio_ && !audio_track_index_) {
     DVLOG(1) << __FUNCTION__ << ": delaying until audio track ready.";
+    if (is_key_frame) {
+      most_recent_encoded_video_keyframe_ = std::move(encoded_data);
+      saved_keyframe_timestamp_ = timestamp;
+    }
     return;
   }
 
-  most_recent_timestamp_ =
-      std::max(most_recent_timestamp_, timestamp - first_frame_timestamp_);
-  segment_.AddFrame(reinterpret_cast<const uint8_t*>(encoded_data->data()),
-                    encoded_data->size(), video_track_index_,
-                    most_recent_timestamp_.InMicroseconds() *
-                        base::Time::kNanosecondsPerMicrosecond,
-                    is_key_frame);
+  // If have a saved keyframe, add it first.
+  if (most_recent_encoded_video_keyframe_.get())
+    AddFrame(std::move(most_recent_encoded_video_keyframe_), video_track_index_,
+             saved_keyframe_timestamp_, true /* is_key_frame */);
+
+  AddFrame(std::move(encoded_data), video_track_index_, timestamp,
+           is_key_frame);
 }
 
 void WebmMuxer::OnEncodedAudio(const media::AudioParameters& params,
@@ -158,13 +162,13 @@
     return;
   }
 
-  most_recent_timestamp_ =
-      std::max(most_recent_timestamp_, timestamp - first_frame_timestamp_);
-  segment_.AddFrame(reinterpret_cast<const uint8_t*>(encoded_data->data()),
-                    encoded_data->size(), audio_track_index_,
-                    most_recent_timestamp_.InMicroseconds() *
-                        base::Time::kNanosecondsPerMicrosecond,
-                    true /* is_key_frame -- always true for audio */);
+  // If have a saved keyframe, add it first.
+  if (most_recent_encoded_video_keyframe_.get())
+    AddFrame(std::move(most_recent_encoded_video_keyframe_), video_track_index_,
+             saved_keyframe_timestamp_, true /* is_key_frame */);
+
+  AddFrame(std::move(encoded_data), audio_track_index_, timestamp,
+           true /* is_key_frame -- always true for audio */);
 }
 
 void WebmMuxer::AddVideoTrack(const gfx::Size& frame_size, double frame_rate) {
@@ -253,4 +257,22 @@
       << "Can't go back in a live WebM stream.";
 }
 
+void WebmMuxer::AddFrame(scoped_ptr<std::string> encoded_data,
+                         uint8_t track_index,
+                         base::TimeTicks timestamp,
+                         bool is_key_frame) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK(!has_video_ || video_track_index_);
+  DCHECK(!has_audio_ || audio_track_index_);
+
+  most_recent_timestamp_ =
+      std::max(most_recent_timestamp_, timestamp - first_frame_timestamp_);
+
+  segment_.AddFrame(reinterpret_cast<const uint8_t*>(encoded_data->data()),
+                    encoded_data->size(), track_index,
+                    most_recent_timestamp_.InMicroseconds() *
+                        base::Time::kNanosecondsPerMicrosecond,
+                    is_key_frame);
+}
+
 }  // namespace media
diff --git a/media/capture/webm_muxer.h b/media/capture/webm_muxer.h
index f5171b8..9a4287f 100644
--- a/media/capture/webm_muxer.h
+++ b/media/capture/webm_muxer.h
@@ -77,6 +77,12 @@
   void ElementStartNotify(mkvmuxer::uint64 element_id,
                           mkvmuxer::int64 position) override;
 
+  // Helper to simplify saving frames.
+  void AddFrame(scoped_ptr<std::string> encoded_data,
+                uint8_t track_index,
+                base::TimeTicks timestamp,
+                bool is_key_frame);
+
   // Used to DCHECK that we are called on the correct thread.
   base::ThreadChecker thread_checker_;
 
@@ -106,6 +112,10 @@
   // The MkvMuxer active element.
   mkvmuxer::Segment segment_;
 
+  // Save the most recent video keyframe if we're waiting for audio to come in.
+  scoped_ptr<std::string> most_recent_encoded_video_keyframe_;
+  base::TimeTicks saved_keyframe_timestamp_;
+
   DISALLOW_COPY_AND_ASSIGN(WebmMuxer);
 };
 
diff --git a/media/capture/webm_muxer_unittest.cc b/media/capture/webm_muxer_unittest.cc
index 8b45e1df..a0754b58 100644
--- a/media/capture/webm_muxer_unittest.cc
+++ b/media/capture/webm_muxer_unittest.cc
@@ -15,8 +15,14 @@
 #include "testing/gtest/include/gtest/gtest.h"
 
 using ::testing::_;
+using ::testing::AllOf;
+using ::testing::AnyNumber;
 using ::testing::AtLeast;
+using ::testing::Eq;
+using ::testing::InSequence;
 using ::testing::Mock;
+using ::testing::Not;
+using ::testing::Sequence;
 using ::testing::TestWithParam;
 using ::testing::ValuesIn;
 using ::testing::WithArgs;
@@ -87,7 +93,7 @@
 // This test sends two frames and checks that the WriteCallback is called with
 // appropriate params in both cases.
 TEST_P(WebmMuxerTest, OnEncodedVideoTwoFrames) {
-  if (GetParam().num_video_tracks == 0)
+  if (GetParam().num_audio_tracks > 0)
     return;
 
   const gfx::Size frame_size(160, 80);
@@ -97,8 +103,8 @@
 
   EXPECT_CALL(*this, WriteCallback(_))
       .Times(AtLeast(1))
-      .WillRepeatedly(WithArgs<0>(
-          Invoke(this, &WebmMuxerTest::SaveEncodedDataLen)));
+      .WillRepeatedly(
+          WithArgs<0>(Invoke(this, &WebmMuxerTest::SaveEncodedDataLen)));
   webm_muxer_.OnEncodedVideo(video_frame,
                              make_scoped_ptr(new std::string(encoded_data)),
                              base::TimeTicks::Now(),
@@ -114,8 +120,8 @@
   const int64_t begin_of_second_block = accumulated_position_;
   EXPECT_CALL(*this, WriteCallback(_))
       .Times(AtLeast(1))
-      .WillRepeatedly(WithArgs<0>(
-          Invoke(this, &WebmMuxerTest::SaveEncodedDataLen)));
+      .WillRepeatedly(
+          WithArgs<0>(Invoke(this, &WebmMuxerTest::SaveEncodedDataLen)));
   webm_muxer_.OnEncodedVideo(video_frame,
                              make_scoped_ptr(new std::string(encoded_data)),
                              base::TimeTicks::Now(),
@@ -132,7 +138,7 @@
 }
 
 TEST_P(WebmMuxerTest, OnEncodedAudioTwoFrames) {
-  if (GetParam().num_audio_tracks == 0)
+  if (GetParam().num_video_tracks > 0)
     return;
 
   int sample_rate = 48000;
@@ -179,11 +185,59 @@
             accumulated_position_);
 }
 
+// Currently, when WebmMuxer is told it will have both audio and video tracks,
+// it drops data until it's receiving data for _both_ tracks, to avoid issues
+// related to writing the webm header.
+// This test verifies that when video data comes before audio data, we save the
+// most recent video keyframe and add it to the video track as soon as audio
+// data comes.
+TEST_P(WebmMuxerTest, VideoKeyframeIsSaved) {
+  // This test is only relevant if we have both kinds of tracks.
+  if (GetParam().num_video_tracks == 0 || GetParam().num_audio_tracks == 0)
+    return;
+
+  // First send a video keyframe
+  const gfx::Size frame_size(160, 80);
+  const scoped_refptr<VideoFrame> video_frame =
+      VideoFrame::CreateBlackFrame(frame_size);
+  const std::string encoded_video("thisisanencodedvideopacket");
+  // Won't write anything.
+  webm_muxer_.OnEncodedVideo(video_frame,
+                             make_scoped_ptr(new std::string(encoded_video)),
+                             base::TimeTicks::Now(), true /* keyframe */);
+
+  // Then send some audio. The header will be written and muxing will proceed
+  // normally.
+  int sample_rate = 48000;
+  int bits_per_sample = 16;
+  int frames_per_buffer = 480;
+  media::AudioParameters audio_params(
+      media::AudioParameters::Format::AUDIO_PCM_LOW_LATENCY,
+      media::CHANNEL_LAYOUT_MONO, sample_rate, bits_per_sample,
+      frames_per_buffer);
+  const std::string encoded_audio("thisisanencodedaudiopacket");
+
+  // We should first get the video keyframe, then the audio frame.
+  Sequence s;
+  EXPECT_CALL(*this, WriteCallback(Eq(encoded_video))).Times(1).InSequence(s);
+  EXPECT_CALL(*this, WriteCallback(Eq(encoded_audio))).Times(1).InSequence(s);
+  // We'll also get lots of other header-related stuff.
+  EXPECT_CALL(*this, WriteCallback(
+                         AllOf(Not(Eq(encoded_video)), Not(Eq(encoded_audio)))))
+      .Times(AnyNumber());
+  webm_muxer_.OnEncodedAudio(audio_params,
+                             make_scoped_ptr(new std::string(encoded_audio)),
+                             base::TimeTicks::Now());
+}
+
 const kTestParams kTestCases[] = {
     // TODO: consider not enumerating every combination by hand.
     {kCodecVP8, 1 /* num_video_tracks */, 0 /*num_audio_tracks*/},
-    {kCodecVP9, 1, 0},
     {kCodecVP8, 0, 1},
+    {kCodecVP8, 1, 1},
+    {kCodecVP9, 1, 0},
+    {kCodecVP9, 0, 1},
+    {kCodecVP9, 1, 1},
 };
 
 INSTANTIATE_TEST_CASE_P(, WebmMuxerTest, ValuesIn(kTestCases));
diff --git a/media/cast/net/pacing/paced_sender.cc b/media/cast/net/pacing/paced_sender.cc
index b8642b1..61166da 100644
--- a/media/cast/net/pacing/paced_sender.cc
+++ b/media/cast/net/pacing/paced_sender.cc
@@ -31,10 +31,12 @@
 DedupInfo::DedupInfo() : last_byte_acked_for_audio(0) {}
 
 // static
-PacketKey PacedPacketSender::MakePacketKey(const base::TimeTicks& ticks,
+PacketKey PacedPacketSender::MakePacketKey(PacketKey::PacketType packet_type,
+                                           uint32 frame_id,
                                            uint32 ssrc,
                                            uint16 packet_id) {
-  return std::make_pair(ticks, std::make_pair(ssrc, packet_id));
+  PacketKey key{packet_type, frame_id, ssrc, packet_id};
+  return key;
 }
 
 PacedSender::PacketSendRecord::PacketSendRecord()
@@ -125,7 +127,7 @@
   // packet Y sent just before X. Reject retransmission of X if ACK for
   // Y has not been received.
   // Only do this for video packets.
-  if (packet_key.second.first == video_ssrc_) {
+  if (packet_key.ssrc == video_ssrc_) {
     if (dedup_info.last_byte_acked_for_audio &&
         it->second.last_byte_sent_for_audio &&
         dedup_info.last_byte_acked_for_audio <
@@ -169,9 +171,9 @@
 
 bool PacedSender::SendRtcpPacket(uint32 ssrc, PacketRef packet) {
   if (state_ == State_TransportBlocked) {
-    priority_packet_list_[
-        PacedPacketSender::MakePacketKey(base::TimeTicks(), ssrc, 0)] =
-        make_pair(PacketType_RTCP, packet);
+    PacketKey key =
+        PacedPacketSender::MakePacketKey(PacketKey::RTCP, 0, ssrc, 0);
+    priority_packet_list_[key] = make_pair(PacketType_RTCP, packet);
   } else {
     // We pass the RTCP packets straight through.
     if (!transport_->SendPacket(
@@ -204,7 +206,7 @@
 
 bool PacedSender::IsHighPriority(const PacketKey& packet_key) const {
   return std::find(priority_ssrcs_.begin(), priority_ssrcs_.end(),
-                   packet_key.second.first) != priority_ssrcs_.end();
+                   packet_key.ssrc) != priority_ssrcs_.end();
 }
 
 bool PacedSender::empty() const {
@@ -298,7 +300,7 @@
     send_record.last_byte_sent_for_audio = GetLastByteSentForSsrc(audio_ssrc_);
     send_history_[packet_key] = send_record;
     send_history_buffer_[packet_key] = send_record;
-    last_byte_sent_[packet_key.second.first] = send_record.last_byte_sent;
+    last_byte_sent_[packet_key.ssrc] = send_record.last_byte_sent;
 
     if (socket_blocked) {
       state_ = State_TransportBlocked;
diff --git a/media/cast/net/pacing/paced_sender.h b/media/cast/net/pacing/paced_sender.h
index a5fcfd17..f37ebe7 100644
--- a/media/cast/net/pacing/paced_sender.h
+++ b/media/cast/net/pacing/paced_sender.h
@@ -6,6 +6,7 @@
 #define MEDIA_CAST_NET_PACING_PACED_SENDER_H_
 
 #include <map>
+#include <tuple>
 #include <vector>
 
 #include "base/basictypes.h"
@@ -26,15 +27,26 @@
 static const size_t kTargetBurstSize = 10;
 static const size_t kMaxBurstSize = 20;
 
-// Use std::pair for free comparison operators.
-// { capture_time, ssrc, packet_id }
 // The PacketKey is designed to meet two criteria:
 // 1. When we re-send the same packet again, we can use the packet key
 //    to identify it so that we can de-duplicate packets in the queue.
 // 2. The sort order of the PacketKey determines the order that packets
-//    are sent out. Using the capture_time as the first member basically
-//    means that older packets are sent first.
-typedef std::pair<base::TimeTicks, std::pair<uint32, uint16> > PacketKey;
+//    are sent out.
+// 3. The PacketKey is unique for each RTP (frame) packet.
+struct PacketKey {
+  enum PacketType { RTCP = 0, RTP = 1 };
+
+  PacketType packet_type;
+  uint32 frame_id;
+  uint32 ssrc;
+  uint16 packet_id;
+
+  bool operator<(const PacketKey& key) const {
+    return std::tie(packet_type, frame_id, ssrc, packet_id) <
+           std::tie(key.packet_type, key.frame_id, key.ssrc, key.packet_id);
+  }
+};
+
 typedef std::vector<std::pair<PacketKey, PacketRef> > SendPacketVector;
 
 // Information used to deduplicate retransmission packets.
@@ -68,7 +80,8 @@
 
   virtual ~PacedPacketSender() {}
 
-  static PacketKey MakePacketKey(const base::TimeTicks& ticks,
+  static PacketKey MakePacketKey(PacketKey::PacketType,
+                                 uint32 frame_id,
                                  uint32 ssrc,
                                  uint16 packet_id);
 };
diff --git a/media/cast/net/pacing/paced_sender_unittest.cc b/media/cast/net/pacing/paced_sender_unittest.cc
index 13d5afd..1df7415 100644
--- a/media/cast/net/pacing/paced_sender_unittest.cc
+++ b/media/cast/net/pacing/paced_sender_unittest.cc
@@ -57,7 +57,7 @@
 
 class PacedSenderTest : public ::testing::Test {
  protected:
-  PacedSenderTest() {
+  PacedSenderTest() : frame_id_(0) {
     testing_clock_.Advance(
         base::TimeDelta::FromMilliseconds(kStartMillisecond));
     task_runner_ = new test::FakeSingleThreadTaskRunner(&testing_clock_);
@@ -77,14 +77,10 @@
                                           bool audio) {
     DCHECK_GE(packet_size, 12u);
     SendPacketVector packets;
-    base::TimeTicks frame_tick = testing_clock_.NowTicks();
-    // Advance the clock so that we don't get the same frame_tick
-    // next time this function is called.
-    testing_clock_.Advance(base::TimeDelta::FromMilliseconds(1));
     for (int i = 0; i < num_of_packets_in_frame; ++i) {
       PacketKey key = PacedPacketSender::MakePacketKey(
-          frame_tick,
-          audio ? kAudioSsrc : kVideoSsrc, // ssrc
+          PacketKey::RTP, frame_id_,
+          audio ? kAudioSsrc : kVideoSsrc,  // ssrc
           i);
 
       PacketRef packet(new base::RefCountedData<Packet>);
@@ -102,6 +98,9 @@
       CHECK(success);
       packets.push_back(std::make_pair(key, packet));
     }
+    // Increase |frame_id_| so that we don't get the same key next time this
+    // function is called.
+    ++frame_id_;
     return packets;
   }
 
@@ -124,6 +123,7 @@
   TestPacketSender mock_transport_;
   scoped_refptr<test::FakeSingleThreadTaskRunner> task_runner_;
   scoped_ptr<PacedSender> paced_sender_;
+  uint32 frame_id_;
 
   DISALLOW_COPY_AND_ASSIGN(PacedSenderTest);
 };
diff --git a/media/cast/net/rtp/packet_storage_unittest.cc b/media/cast/net/rtp/packet_storage_unittest.cc
index 7dc5a53a..699368f 100644
--- a/media/cast/net/rtp/packet_storage_unittest.cc
+++ b/media/cast/net/rtp/packet_storage_unittest.cc
@@ -24,7 +24,6 @@
 static void StoreFrames(size_t number_of_frames,
                         uint32 first_frame_id,
                         PacketStorage* storage) {
-  const base::TimeTicks kTicks;
   const int kSsrc = 1;
   for (size_t i = 0; i < number_of_frames; ++i) {
     SendPacketVector packets;
@@ -32,10 +31,10 @@
     const size_t kNumberOfPackets = i + 1;
     for (size_t j = 0; j < kNumberOfPackets; ++j) {
       Packet test_packet(1, 0);
-      packets.push_back(
-          std::make_pair(PacedPacketSender::MakePacketKey(
-                             kTicks, kSsrc, base::checked_cast<uint16>(j)),
-                         new base::RefCountedData<Packet>(test_packet)));
+      packets.push_back(std::make_pair(
+          PacedPacketSender::MakePacketKey(PacketKey::RTP, i, kSsrc,
+                                           base::checked_cast<uint16>(j)),
+          new base::RefCountedData<Packet>(test_packet)));
     }
     storage->StoreFrame(first_frame_id, packets);
     ++first_frame_id;
diff --git a/media/cast/net/rtp/rtp_packetizer.cc b/media/cast/net/rtp/rtp_packetizer.cc
index ca9834c..6eb3230 100644
--- a/media/cast/net/rtp/rtp_packetizer.cc
+++ b/media/cast/net/rtp/rtp_packetizer.cc
@@ -107,10 +107,8 @@
                         data_iter + payload_length);
     data_iter += payload_length;
 
-    const PacketKey key =
-        PacedPacketSender::MakePacketKey(frame.reference_time,
-                                         config_.ssrc,
-                                         packet_id_++);
+    const PacketKey key = PacedPacketSender::MakePacketKey(
+        PacketKey::RTP, frame.frame_id, config_.ssrc, packet_id_++);
     packets.push_back(make_pair(key, packet));
 
     // Update stats.
diff --git a/media/cast/net/rtp/rtp_sender.cc b/media/cast/net/rtp/rtp_sender.cc
index f24f346..bd822e8 100644
--- a/media/cast/net/rtp/rtp_sender.cc
+++ b/media/cast/net/rtp/rtp_sender.cc
@@ -77,7 +77,7 @@
     for (SendPacketVector::const_iterator it = stored_packets->begin();
          it != stored_packets->end(); ++it) {
       const PacketKey& packet_key = it->first;
-      const uint16 packet_id = packet_key.second.second;
+      const uint16 packet_id = packet_key.packet_id;
 
       // Should we resend the packet?
       bool resend = resend_all;
diff --git a/media/cdm/cdm_helpers.cc b/media/cdm/cdm_helpers.cc
new file mode 100644
index 0000000..f413dfa
--- /dev/null
+++ b/media/cdm/cdm_helpers.cc
@@ -0,0 +1,137 @@
+// 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.
+
+#include "media/cdm/cdm_helpers.h"
+
+#if defined(USE_PPAPI_CDM_ADAPTER)
+// When building the ppapi adapter do not include any non-trivial base/ headers.
+#include "ppapi/cpp/logging.h"
+#define PLATFORM_DCHECK PP_DCHECK
+#else
+#include "base/logging.h"
+#define PLATFORM_DCHECK DCHECK
+#endif
+
+namespace media {
+
+DecryptedBlockImpl::DecryptedBlockImpl() : buffer_(nullptr), timestamp_(0) {}
+
+DecryptedBlockImpl::~DecryptedBlockImpl() {
+  if (buffer_)
+    buffer_->Destroy();
+}
+
+void DecryptedBlockImpl::SetDecryptedBuffer(cdm::Buffer* buffer) {
+  buffer_ = buffer;
+}
+
+cdm::Buffer* DecryptedBlockImpl::DecryptedBuffer() {
+  return buffer_;
+}
+
+void DecryptedBlockImpl::SetTimestamp(int64_t timestamp) {
+  timestamp_ = timestamp;
+}
+
+int64_t DecryptedBlockImpl::Timestamp() const {
+  return timestamp_;
+}
+
+VideoFrameImpl::VideoFrameImpl()
+    : format_(cdm::kUnknownVideoFormat), frame_buffer_(nullptr), timestamp_(0) {
+  for (uint32_t i = 0; i < kMaxPlanes; ++i) {
+    plane_offsets_[i] = 0;
+    strides_[i] = 0;
+  }
+}
+
+VideoFrameImpl::~VideoFrameImpl() {
+  if (frame_buffer_)
+    frame_buffer_->Destroy();
+}
+
+void VideoFrameImpl::SetFormat(cdm::VideoFormat format) {
+  format_ = format;
+}
+
+cdm::VideoFormat VideoFrameImpl::Format() const {
+  return format_;
+}
+
+void VideoFrameImpl::SetSize(cdm::Size size) {
+  size_ = size;
+}
+
+cdm::Size VideoFrameImpl::Size() const {
+  return size_;
+}
+
+void VideoFrameImpl::SetFrameBuffer(cdm::Buffer* frame_buffer) {
+  frame_buffer_ = frame_buffer;
+}
+
+cdm::Buffer* VideoFrameImpl::FrameBuffer() {
+  return frame_buffer_;
+}
+
+void VideoFrameImpl::SetPlaneOffset(cdm::VideoFrame::VideoPlane plane,
+                                    uint32_t offset) {
+  PLATFORM_DCHECK(plane < kMaxPlanes);
+  plane_offsets_[plane] = offset;
+}
+
+uint32_t VideoFrameImpl::PlaneOffset(VideoPlane plane) {
+  PLATFORM_DCHECK(plane < kMaxPlanes);
+  return plane_offsets_[plane];
+}
+
+void VideoFrameImpl::SetStride(VideoPlane plane, uint32_t stride) {
+  PLATFORM_DCHECK(plane < kMaxPlanes);
+  strides_[plane] = stride;
+}
+
+uint32_t VideoFrameImpl::Stride(VideoPlane plane) {
+  PLATFORM_DCHECK(plane < kMaxPlanes);
+  return strides_[plane];
+}
+
+void VideoFrameImpl::SetTimestamp(int64_t timestamp) {
+  timestamp_ = timestamp;
+}
+
+int64_t VideoFrameImpl::Timestamp() const {
+  return timestamp_;
+}
+
+AudioFramesImpl::AudioFramesImpl()
+    : buffer_(nullptr), format_(cdm::kUnknownAudioFormat) {}
+
+AudioFramesImpl::~AudioFramesImpl() {
+  if (buffer_)
+    buffer_->Destroy();
+}
+
+void AudioFramesImpl::SetFrameBuffer(cdm::Buffer* buffer) {
+  buffer_ = buffer;
+}
+
+cdm::Buffer* AudioFramesImpl::FrameBuffer() {
+  return buffer_;
+}
+
+void AudioFramesImpl::SetFormat(cdm::AudioFormat format) {
+  format_ = format;
+}
+
+cdm::AudioFormat AudioFramesImpl::Format() const {
+  return format_;
+}
+
+cdm::Buffer* AudioFramesImpl::PassFrameBuffer() {
+  cdm::Buffer* temp_buffer = buffer_;
+  buffer_ = nullptr;
+  return temp_buffer;
+}
+
+}  // namespace media
diff --git a/media/cdm/cdm_helpers.h b/media/cdm/cdm_helpers.h
new file mode 100644
index 0000000..a058f431
--- /dev/null
+++ b/media/cdm/cdm_helpers.h
@@ -0,0 +1,96 @@
+// 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.
+
+#ifndef MEDIA_CDM_CDM_HELPERS_H_
+#define MEDIA_CDM_CDM_HELPERS_H_
+
+#include "base/basictypes.h"
+#include "media/cdm/api/content_decryption_module.h"
+
+namespace media {
+
+class DecryptedBlockImpl : public cdm::DecryptedBlock {
+ public:
+  DecryptedBlockImpl();
+  ~DecryptedBlockImpl() final;
+
+  // cdm::DecryptedBlock implementation.
+  void SetDecryptedBuffer(cdm::Buffer* buffer) final;
+  cdm::Buffer* DecryptedBuffer() final;
+  void SetTimestamp(int64_t timestamp) final;
+  int64_t Timestamp() const final;
+
+ private:
+  cdm::Buffer* buffer_;
+  int64_t timestamp_;
+
+  DISALLOW_COPY_AND_ASSIGN(DecryptedBlockImpl);
+};
+
+class VideoFrameImpl : public cdm::VideoFrame {
+ public:
+  VideoFrameImpl();
+  ~VideoFrameImpl() final;
+
+  // cdm::VideoFrame implementation.
+  void SetFormat(cdm::VideoFormat format) final;
+  cdm::VideoFormat Format() const final;
+  void SetSize(cdm::Size size) final;
+  cdm::Size Size() const final;
+  void SetFrameBuffer(cdm::Buffer* frame_buffer) final;
+  cdm::Buffer* FrameBuffer() final;
+  void SetPlaneOffset(cdm::VideoFrame::VideoPlane plane, uint32_t offset) final;
+  uint32_t PlaneOffset(VideoPlane plane) final;
+  void SetStride(VideoPlane plane, uint32_t stride) final;
+  uint32_t Stride(VideoPlane plane) final;
+  void SetTimestamp(int64_t timestamp) final;
+  int64_t Timestamp() const final;
+
+ private:
+  // The video buffer format.
+  cdm::VideoFormat format_;
+
+  // Width and height of the video frame.
+  cdm::Size size_;
+
+  // The video frame buffer.
+  cdm::Buffer* frame_buffer_;
+
+  // Array of data pointers to each plane in the video frame buffer.
+  uint32_t plane_offsets_[kMaxPlanes];
+
+  // Array of strides for each plane, typically greater or equal to the width
+  // of the surface divided by the horizontal sampling period.  Note that
+  // strides can be negative.
+  uint32_t strides_[kMaxPlanes];
+
+  // Presentation timestamp in microseconds.
+  int64_t timestamp_;
+
+  DISALLOW_COPY_AND_ASSIGN(VideoFrameImpl);
+};
+
+class AudioFramesImpl : public cdm::AudioFrames {
+ public:
+  AudioFramesImpl();
+  ~AudioFramesImpl() final;
+
+  // cdm::AudioFrames implementation.
+  void SetFrameBuffer(cdm::Buffer* buffer) final;
+  cdm::Buffer* FrameBuffer() final;
+  void SetFormat(cdm::AudioFormat format) final;
+  cdm::AudioFormat Format() const final;
+
+  cdm::Buffer* PassFrameBuffer();
+
+ private:
+  cdm::Buffer* buffer_;
+  cdm::AudioFormat format_;
+
+  DISALLOW_COPY_AND_ASSIGN(AudioFramesImpl);
+};
+
+}  // namespace media
+
+#endif  // MEDIA_CDM_CDM_HELPERS_H_
diff --git a/media/cdm/cdm_wrapper.h b/media/cdm/cdm_wrapper.h
index f5aef43..eafd3d7 100644
--- a/media/cdm/cdm_wrapper.h
+++ b/media/cdm/cdm_wrapper.h
@@ -321,4 +321,6 @@
 
 }  // namespace media
 
+#undef PLATFORM_DCHECK
+
 #endif  // MEDIA_CDM_CDM_WRAPPER_H_
diff --git a/media/cdm/ppapi/cdm_helpers.h b/media/cdm/ppapi/cdm_helpers.h
deleted file mode 100644
index 5d17fbc..0000000
--- a/media/cdm/ppapi/cdm_helpers.h
+++ /dev/null
@@ -1,223 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MEDIA_CDM_PPAPI_CDM_HELPERS_H_
-#define MEDIA_CDM_PPAPI_CDM_HELPERS_H_
-
-#include <map>
-#include <utility>
-
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-#include "build/build_config.h"
-#include "media/cdm/api/content_decryption_module.h"
-#include "ppapi/c/pp_errors.h"
-#include "ppapi/c/pp_stdint.h"
-#include "ppapi/cpp/dev/buffer_dev.h"
-#include "ppapi/cpp/instance.h"
-#include "ppapi/cpp/logging.h"
-
-namespace media {
-
-class PpbBufferAllocator;
-
-// cdm::Buffer implementation that provides access to memory owned by a
-// pp::Buffer_Dev.
-// This class holds a reference to the Buffer_Dev throughout its lifetime.
-// TODO(xhwang): Find a better name. It's confusing to have PpbBuffer,
-// pp::Buffer_Dev and PPB_Buffer_Dev.
-class PpbBuffer : public cdm::Buffer {
- public:
-  static PpbBuffer* Create(const pp::Buffer_Dev& buffer, uint32_t buffer_id,
-                           PpbBufferAllocator* allocator);
-
-  // cdm::Buffer implementation.
-  void Destroy() override;
-  uint32_t Capacity() const override;
-  uint8_t* Data() override;
-  void SetSize(uint32_t size) override;
-  uint32_t Size() const override { return size_; }
-
-  // Takes the |buffer_| from this class and returns it.
-  // Note: The caller must ensure |allocator->Release()| is called later so that
-  // the buffer can be reused by the allocator.
-  // Since pp::Buffer_Dev is ref-counted, the caller now holds one reference to
-  // the buffer and this class holds no reference. Note that other references
-  // may still exist. For example, PpbBufferAllocator always holds a reference
-  // to all allocated buffers.
-  pp::Buffer_Dev TakeBuffer();
-
-  uint32_t buffer_id() const { return buffer_id_; }
-
- private:
-  PpbBuffer(pp::Buffer_Dev buffer,
-            uint32_t buffer_id,
-            PpbBufferAllocator* allocator);
-  ~PpbBuffer() override;
-
-  pp::Buffer_Dev buffer_;
-  uint32_t buffer_id_;
-  uint32_t size_;
-  PpbBufferAllocator* allocator_;
-
-  DISALLOW_COPY_AND_ASSIGN(PpbBuffer);
-};
-
-class PpbBufferAllocator {
- public:
-  explicit PpbBufferAllocator(pp::Instance* instance)
-      : instance_(instance),
-        next_buffer_id_(1) {}
-  ~PpbBufferAllocator() {}
-
-  cdm::Buffer* Allocate(uint32_t capacity);
-
-  // Releases the buffer with |buffer_id|. A buffer can be recycled after
-  // it is released.
-  void Release(uint32_t buffer_id);
-
- private:
-  typedef std::map<uint32_t, pp::Buffer_Dev> AllocatedBufferMap;
-  typedef std::multimap<uint32_t, std::pair<uint32_t, pp::Buffer_Dev> >
-      FreeBufferMap;
-
-  pp::Buffer_Dev AllocateNewBuffer(uint32_t capacity);
-
-  pp::Instance* const instance_;
-  uint32_t next_buffer_id_;
-  AllocatedBufferMap allocated_buffers_;
-  FreeBufferMap free_buffers_;
-
-  DISALLOW_COPY_AND_ASSIGN(PpbBufferAllocator);
-};
-
-class DecryptedBlockImpl : public cdm::DecryptedBlock {
- public:
-  DecryptedBlockImpl() : buffer_(NULL), timestamp_(0) {}
-  ~DecryptedBlockImpl() override {
-    if (buffer_)
-      buffer_->Destroy();
-  }
-
-  void SetDecryptedBuffer(cdm::Buffer* buffer) override {
-    buffer_ = static_cast<PpbBuffer*>(buffer);
-  }
-  cdm::Buffer* DecryptedBuffer() override { return buffer_; }
-
-  void SetTimestamp(int64_t timestamp) override {
-    timestamp_ = timestamp;
-  }
-  int64_t Timestamp() const override { return timestamp_; }
-
- private:
-  PpbBuffer* buffer_;
-  int64_t timestamp_;
-
-  DISALLOW_COPY_AND_ASSIGN(DecryptedBlockImpl);
-};
-
-class VideoFrameImpl : public cdm::VideoFrame {
- public:
-  VideoFrameImpl();
-  ~VideoFrameImpl() override;
-
-  void SetFormat(cdm::VideoFormat format) override {
-    format_ = format;
-  }
-  cdm::VideoFormat Format() const override { return format_; }
-
-  void SetSize(cdm::Size size) override { size_ = size; }
-  cdm::Size Size() const override { return size_; }
-
-  void SetFrameBuffer(cdm::Buffer* frame_buffer) override {
-    frame_buffer_ = static_cast<PpbBuffer*>(frame_buffer);
-  }
-  cdm::Buffer* FrameBuffer() override { return frame_buffer_; }
-
-  void SetPlaneOffset(cdm::VideoFrame::VideoPlane plane,
-                      uint32_t offset) override {
-    PP_DCHECK(plane < kMaxPlanes);
-    plane_offsets_[plane] = offset;
-  }
-  uint32_t PlaneOffset(VideoPlane plane) override {
-    PP_DCHECK(plane < kMaxPlanes);
-    return plane_offsets_[plane];
-  }
-
-  void SetStride(VideoPlane plane, uint32_t stride) override {
-    PP_DCHECK(plane < kMaxPlanes);
-    strides_[plane] = stride;
-  }
-  uint32_t Stride(VideoPlane plane) override {
-    PP_DCHECK(plane < kMaxPlanes);
-    return strides_[plane];
-  }
-
-  void SetTimestamp(int64_t timestamp) override {
-    timestamp_ = timestamp;
-  }
-  int64_t Timestamp() const override { return timestamp_; }
-
- private:
-  // The video buffer format.
-  cdm::VideoFormat format_;
-
-  // Width and height of the video frame.
-  cdm::Size size_;
-
-  // The video frame buffer.
-  PpbBuffer* frame_buffer_;
-
-  // Array of data pointers to each plane in the video frame buffer.
-  uint32_t plane_offsets_[kMaxPlanes];
-
-  // Array of strides for each plane, typically greater or equal to the width
-  // of the surface divided by the horizontal sampling period.  Note that
-  // strides can be negative.
-  uint32_t strides_[kMaxPlanes];
-
-  // Presentation timestamp in microseconds.
-  int64_t timestamp_;
-
-  DISALLOW_COPY_AND_ASSIGN(VideoFrameImpl);
-};
-
-class AudioFramesImpl : public cdm::AudioFrames {
- public:
-  AudioFramesImpl() : buffer_(NULL), format_(cdm::kUnknownAudioFormat) {}
-  ~AudioFramesImpl() override {
-    if (buffer_)
-      buffer_->Destroy();
-  }
-
-  // AudioFrames implementation.
-  void SetFrameBuffer(cdm::Buffer* buffer) override {
-    buffer_ = static_cast<PpbBuffer*>(buffer);
-  }
-  cdm::Buffer* FrameBuffer() override {
-    return buffer_;
-  }
-  void SetFormat(cdm::AudioFormat format) override {
-    format_ = format;
-  }
-  cdm::AudioFormat Format() const override {
-    return format_;
-  }
-
-  cdm::Buffer* PassFrameBuffer() {
-    PpbBuffer* temp_buffer = buffer_;
-    buffer_ = NULL;
-    return temp_buffer;
-  }
-
- private:
-  PpbBuffer* buffer_;
-  cdm::AudioFormat format_;
-
-  DISALLOW_COPY_AND_ASSIGN(AudioFramesImpl);
-};
-
-}  // namespace media
-
-#endif  // MEDIA_CDM_PPAPI_CDM_HELPERS_H_
diff --git a/media/cdm/ppapi/ppapi_cdm_adapter.gni b/media/cdm/ppapi/ppapi_cdm_adapter.gni
index e7cf90ff..b356db3f 100644
--- a/media/cdm/ppapi/ppapi_cdm_adapter.gni
+++ b/media/cdm/ppapi/ppapi_cdm_adapter.gni
@@ -20,16 +20,18 @@
     defines += [ "USE_PPAPI_CDM_ADAPTER" ]
     sources += [
       "//media/cdm/api/content_decryption_module.h",
+      "//media/cdm/cdm_helpers.cc",
+      "//media/cdm/cdm_helpers.h",
       "//media/cdm/cdm_wrapper.h",
       "//media/cdm/ppapi/cdm_file_io_impl.cc",
       "//media/cdm/ppapi/cdm_file_io_impl.h",
-      "//media/cdm/ppapi/cdm_helpers.cc",
-      "//media/cdm/ppapi/cdm_helpers.h",
       "//media/cdm/ppapi/cdm_logging.cc",
       "//media/cdm/ppapi/cdm_logging.h",
       "//media/cdm/ppapi/linked_ptr.h",
       "//media/cdm/ppapi/ppapi_cdm_adapter.cc",
       "//media/cdm/ppapi/ppapi_cdm_adapter.h",
+      "//media/cdm/ppapi/ppapi_cdm_buffer.cc",
+      "//media/cdm/ppapi/ppapi_cdm_buffer.h",
       "//media/cdm/supported_cdm_versions.cc",
       "//media/cdm/supported_cdm_versions.h",
     ]
diff --git a/media/cdm/ppapi/ppapi_cdm_adapter.h b/media/cdm/ppapi/ppapi_cdm_adapter.h
index 470bc9a5..989bd456 100644
--- a/media/cdm/ppapi/ppapi_cdm_adapter.h
+++ b/media/cdm/ppapi/ppapi_cdm_adapter.h
@@ -12,9 +12,10 @@
 #include "base/compiler_specific.h"
 #include "build/build_config.h"
 #include "media/cdm/api/content_decryption_module.h"
+#include "media/cdm/cdm_helpers.h"
 #include "media/cdm/cdm_wrapper.h"
-#include "media/cdm/ppapi/cdm_helpers.h"
 #include "media/cdm/ppapi/linked_ptr.h"
+#include "media/cdm/ppapi/ppapi_cdm_buffer.h"
 #include "ppapi/c/pp_stdint.h"
 #include "ppapi/c/private/pp_content_decryptor.h"
 #include "ppapi/cpp/completion_callback.h"
diff --git a/media/cdm/ppapi/cdm_helpers.cc b/media/cdm/ppapi/ppapi_cdm_buffer.cc
similarity index 90%
rename from media/cdm/ppapi/cdm_helpers.cc
rename to media/cdm/ppapi/ppapi_cdm_buffer.cc
index 00e7595a..3d34512 100644
--- a/media/cdm/ppapi/cdm_helpers.cc
+++ b/media/cdm/ppapi/ppapi_cdm_buffer.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "media/cdm/ppapi/cdm_helpers.h"
+#include "media/cdm/ppapi/ppapi_cdm_buffer.h"
 
 #include <algorithm>
 
@@ -56,8 +56,7 @@
 PpbBuffer::PpbBuffer(pp::Buffer_Dev buffer,
                      uint32_t buffer_id,
                      PpbBufferAllocator* allocator)
-    : buffer_(buffer), buffer_id_(buffer_id), size_(0), allocator_(allocator) {
-}
+    : buffer_(buffer), buffer_id_(buffer_id), size_(0), allocator_(allocator) {}
 
 PpbBuffer::~PpbBuffer() {
   PP_DCHECK(!buffer_id_ == buffer_.is_null());
@@ -130,19 +129,4 @@
   return pp::Buffer_Dev(instance_, capacity + kBufferPadding);
 }
 
-VideoFrameImpl::VideoFrameImpl()
-    : format_(cdm::kUnknownVideoFormat),
-      frame_buffer_(NULL),
-      timestamp_(0) {
-  for (uint32_t i = 0; i < kMaxPlanes; ++i) {
-    plane_offsets_[i] = 0;
-    strides_[i] = 0;
-  }
-}
-
-VideoFrameImpl::~VideoFrameImpl() {
-  if (frame_buffer_)
-    frame_buffer_->Destroy();
-}
-
 }  // namespace media
diff --git a/media/cdm/ppapi/ppapi_cdm_buffer.h b/media/cdm/ppapi/ppapi_cdm_buffer.h
new file mode 100644
index 0000000..2335a004
--- /dev/null
+++ b/media/cdm/ppapi/ppapi_cdm_buffer.h
@@ -0,0 +1,97 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MEDIA_CDM_PPAPI_PPAPI_CDM_BUFFER_H_
+#define MEDIA_CDM_PPAPI_PPAPI_CDM_BUFFER_H_
+
+#include <map>
+#include <utility>
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "build/build_config.h"
+#include "media/cdm/api/content_decryption_module.h"
+#include "ppapi/c/pp_errors.h"
+#include "ppapi/c/pp_stdint.h"
+#include "ppapi/cpp/dev/buffer_dev.h"
+#include "ppapi/cpp/instance.h"
+#include "ppapi/cpp/logging.h"
+
+namespace media {
+
+class PpbBufferAllocator;
+
+// cdm::Buffer implementation that provides access to memory owned by a
+// pp::Buffer_Dev.
+// This class holds a reference to the Buffer_Dev throughout its lifetime.
+// TODO(xhwang): Find a better name. It's confusing to have PpbBuffer,
+// pp::Buffer_Dev and PPB_Buffer_Dev.
+class PpbBuffer : public cdm::Buffer {
+ public:
+  static PpbBuffer* Create(const pp::Buffer_Dev& buffer,
+                           uint32_t buffer_id,
+                           PpbBufferAllocator* allocator);
+
+  // cdm::Buffer implementation.
+  void Destroy() override;
+  uint32_t Capacity() const override;
+  uint8_t* Data() override;
+  void SetSize(uint32_t size) override;
+  uint32_t Size() const override { return size_; }
+
+  // Takes the |buffer_| from this class and returns it.
+  // Note: The caller must ensure |allocator->Release()| is called later so that
+  // the buffer can be reused by the allocator.
+  // Since pp::Buffer_Dev is ref-counted, the caller now holds one reference to
+  // the buffer and this class holds no reference. Note that other references
+  // may still exist. For example, PpbBufferAllocator always holds a reference
+  // to all allocated buffers.
+  pp::Buffer_Dev TakeBuffer();
+
+  uint32_t buffer_id() const { return buffer_id_; }
+
+ private:
+  PpbBuffer(pp::Buffer_Dev buffer,
+            uint32_t buffer_id,
+            PpbBufferAllocator* allocator);
+  ~PpbBuffer() override;
+
+  pp::Buffer_Dev buffer_;
+  uint32_t buffer_id_;
+  uint32_t size_;
+  PpbBufferAllocator* allocator_;
+
+  DISALLOW_COPY_AND_ASSIGN(PpbBuffer);
+};
+
+class PpbBufferAllocator {
+ public:
+  explicit PpbBufferAllocator(pp::Instance* instance)
+      : instance_(instance), next_buffer_id_(1) {}
+  ~PpbBufferAllocator() {}
+
+  cdm::Buffer* Allocate(uint32_t capacity);
+
+  // Releases the buffer with |buffer_id|. A buffer can be recycled after
+  // it is released.
+  void Release(uint32_t buffer_id);
+
+ private:
+  typedef std::map<uint32_t, pp::Buffer_Dev> AllocatedBufferMap;
+  typedef std::multimap<uint32_t, std::pair<uint32_t, pp::Buffer_Dev>>
+      FreeBufferMap;
+
+  pp::Buffer_Dev AllocateNewBuffer(uint32_t capacity);
+
+  pp::Instance* const instance_;
+  uint32_t next_buffer_id_;
+  AllocatedBufferMap allocated_buffers_;
+  FreeBufferMap free_buffers_;
+
+  DISALLOW_COPY_AND_ASSIGN(PpbBufferAllocator);
+};
+
+}  // namespace media
+
+#endif  // MEDIA_CDM_PPAPI_PPAPI_CDM_BUFFER_H_
diff --git a/media/filters/decrypting_video_decoder.cc b/media/filters/decrypting_video_decoder.cc
index 9ec48c9..953826c0 100644
--- a/media/filters/decrypting_video_decoder.cc
+++ b/media/filters/decrypting_video_decoder.cc
@@ -42,7 +42,8 @@
                                         const SetCdmReadyCB& set_cdm_ready_cb,
                                         const InitCB& init_cb,
                                         const OutputCB& output_cb) {
-  DVLOG(2) << "Initialize()";
+  DVLOG(2) << __FUNCTION__ << ": " << config.AsHumanReadableString();
+
   DCHECK(task_runner_->BelongsToCurrentThread());
   DCHECK(state_ == kUninitialized ||
          state_ == kIdle ||
diff --git a/media/filters/ffmpeg_demuxer.cc b/media/filters/ffmpeg_demuxer.cc
index f7a3f48..f041bb6c 100644
--- a/media/filters/ffmpeg_demuxer.cc
+++ b/media/filters/ffmpeg_demuxer.cc
@@ -748,7 +748,6 @@
       text_enabled_(false),
       duration_known_(false),
       encrypted_media_init_data_cb_(encrypted_media_init_data_cb),
-      stream_memory_usage_(0),
       weak_factory_(this) {
   DCHECK(task_runner_.get());
   DCHECK(data_source_);
@@ -925,8 +924,12 @@
 }
 
 int64_t FFmpegDemuxer::GetMemoryUsage() const {
-  base::AutoLock locker(stream_memory_usage_lock_);
-  return stream_memory_usage_;
+  int64_t allocation_size = 0;
+  for (const auto& stream : streams_) {
+    if (stream)
+      allocation_size += stream->MemoryUsage();
+  }
+  return allocation_size;
 }
 
 // Helper for calculating the bitrate of the media based on information stored
@@ -1379,15 +1382,10 @@
     return;
   }
 
-  // Max allowed memory usage, all streams combined.
-  const int64_t kDemuxerMemoryLimit = 150 * 1024 * 1024;
-  const bool is_max_memory_usage_reached =
-      UpdateMemoryUsage() > kDemuxerMemoryLimit;
-
   // Consider the stream as ended if:
   // - either underlying ffmpeg returned an error
   // - or FFMpegDemuxer reached the maximum allowed memory usage.
-  if (result < 0 || is_max_memory_usage_reached) {
+  if (result < 0 || IsMaxMemoryUsageReached()) {
     // Update the duration based on the highest elapsed time across all streams
     // if it was previously unknown.
     if (!duration_known_) {
@@ -1453,16 +1451,24 @@
   return false;
 }
 
-int64_t FFmpegDemuxer::UpdateMemoryUsage() {
+bool FFmpegDemuxer::IsMaxMemoryUsageReached() const {
   DCHECK(task_runner_->BelongsToCurrentThread());
 
-  base::AutoLock locker(stream_memory_usage_lock_);
-  stream_memory_usage_ = 0;
-  for (const auto& stream : streams_) {
-    if (stream)
-      stream_memory_usage_ += stream->MemoryUsage();
+  // Max allowed memory usage, all streams combined.
+  const size_t kDemuxerMemoryLimit = 150 * 1024 * 1024;
+
+  size_t memory_left = kDemuxerMemoryLimit;
+  for (StreamVector::const_iterator iter = streams_.begin();
+       iter != streams_.end(); ++iter) {
+    if (!(*iter))
+      continue;
+
+    size_t stream_memory_usage = (*iter)->MemoryUsage();
+    if (stream_memory_usage > memory_left)
+      return true;
+    memory_left -= stream_memory_usage;
   }
-  return stream_memory_usage_;
+  return false;
 }
 
 void FFmpegDemuxer::StreamHasEnded() {
diff --git a/media/filters/ffmpeg_demuxer.h b/media/filters/ffmpeg_demuxer.h
index 154ff05e..c527b74 100644
--- a/media/filters/ffmpeg_demuxer.h
+++ b/media/filters/ffmpeg_demuxer.h
@@ -233,9 +233,8 @@
   // go over capacity depending on how the file is muxed.
   bool StreamsHaveAvailableCapacity();
 
-  // Updates |stream_memory_usage_| to the memory usage in bytes of all
-  // FFmpegDemuxerStreams.  Returns the current memory usage.
-  int64_t UpdateMemoryUsage();
+  // Returns true if the maximum allowed memory usage has been reached.
+  bool IsMaxMemoryUsageReached() const;
 
   // Signal all FFmpegDemuxerStreams that the stream has ended.
   void StreamHasEnded();
@@ -324,10 +323,6 @@
 
   const EncryptedMediaInitDataCB encrypted_media_init_data_cb_;
 
-  // Last stream size as calculated by UpdateMemoryUsage().
-  mutable base::Lock stream_memory_usage_lock_;
-  int64_t stream_memory_usage_;
-
   // NOTE: Weak pointers must be invalidated before all other member variables.
   base::WeakPtrFactory<FFmpegDemuxer> weak_factory_;
 
diff --git a/media/filters/ffmpeg_demuxer_unittest.cc b/media/filters/ffmpeg_demuxer_unittest.cc
index 1e915b943d..f0386488 100644
--- a/media/filters/ffmpeg_demuxer_unittest.cc
+++ b/media/filters/ffmpeg_demuxer_unittest.cc
@@ -981,7 +981,8 @@
   event.RunAndWaitForStatus(PIPELINE_OK);
 
   // Verify that seeking to the end read only a small portion of the file.
-  // Slow that read sequentially up to the seek point will fail this check.
+  // Slow seeks that read sequentially up to the seek point will read too many
+  // bytes and fail this check.
   int64 file_size = 0;
   ASSERT_TRUE(data_source_->GetSize(&file_size));
   EXPECT_LT(data_source_->bytes_read_for_testing(), (file_size * .25));
diff --git a/media/filters/gpu_video_decoder.cc b/media/filters/gpu_video_decoder.cc
index b7229f0..1185b967 100644
--- a/media/filters/gpu_video_decoder.cc
+++ b/media/filters/gpu_video_decoder.cc
@@ -174,7 +174,10 @@
   }
 
   vda_ = factories_->CreateVideoDecodeAccelerator().Pass();
-  if (!vda_ || !vda_->Initialize(config.profile(), this)) {
+
+  VideoDecodeAccelerator::Config vda_config(config);
+
+  if (!vda_ || !vda_->Initialize(vda_config, this)) {
     DVLOG(1) << "VDA initialization failed.";
     bound_init_cb.Run(false);
     return;
@@ -455,8 +458,10 @@
 
   DCHECK(decoder_texture_target_);
 
+  bool opaque = IsOpaque(config_.format());
+
   scoped_refptr<VideoFrame> frame(VideoFrame::WrapNativeTexture(
-      PIXEL_FORMAT_ARGB,
+      opaque ? PIXEL_FORMAT_XRGB : PIXEL_FORMAT_ARGB,
       gpu::MailboxHolder(pb.texture_mailbox(), gpu::SyncToken(),
                          decoder_texture_target_),
       BindToCurrentLoop(base::Bind(
diff --git a/media/media_cdm_adapter.gyp b/media/media_cdm_adapter.gyp
index 876f884..4049b362 100644
--- a/media/media_cdm_adapter.gyp
+++ b/media/media_cdm_adapter.gyp
@@ -26,13 +26,15 @@
              ],
             'sources': [
               'cdm/api/content_decryption_module.h',
+              'cdm/cdm_helpers.cc',
+              'cdm/cdm_helpers.h',
               'cdm/cdm_wrapper.h',
               'cdm/ppapi/ppapi_cdm_adapter.cc',
               'cdm/ppapi/ppapi_cdm_adapter.h',
+              'cdm/ppapi/ppapi_cdm_buffer.cc',
+              'cdm/ppapi/ppapi_cdm_buffer.h',
               'cdm/ppapi/cdm_file_io_impl.cc',
               'cdm/ppapi/cdm_file_io_impl.h',
-              'cdm/ppapi/cdm_helpers.cc',
-              'cdm/ppapi/cdm_helpers.h',
               'cdm/ppapi/cdm_logging.cc',
               'cdm/ppapi/cdm_logging.h',
               'cdm/ppapi/linked_ptr.h',
diff --git a/media/mojo/services/media_type_converters.cc b/media/mojo/services/media_type_converters.cc
index fc733aa..a4a9ead 100644
--- a/media/mojo/services/media_type_converters.cc
+++ b/media/mojo/services/media_type_converters.cc
@@ -648,7 +648,7 @@
   memcpy(frame->data(media::VideoFrame::kVPlane),
          input->v_data.storage().data(), input->v_data.storage().size());
 
-  return frame.Pass();
+  return frame;
 }
 
 }  // namespace mojo
diff --git a/media/renderers/skcanvas_video_renderer.cc b/media/renderers/skcanvas_video_renderer.cc
index d2f25d63..aa9321a 100644
--- a/media/renderers/skcanvas_video_renderer.cc
+++ b/media/renderers/skcanvas_video_renderer.cc
@@ -147,6 +147,7 @@
     VideoFrame* video_frame,
     const Context3D& context_3d) {
   DCHECK(PIXEL_FORMAT_ARGB == video_frame->format() ||
+         PIXEL_FORMAT_XRGB == video_frame->format() ||
          PIXEL_FORMAT_NV12 == video_frame->format() ||
          PIXEL_FORMAT_UYVY == video_frame->format());
 
diff --git a/media/test/pipeline_integration_test.cc b/media/test/pipeline_integration_test.cc
index 43bb528..255d5eb 100644
--- a/media/test/pipeline_integration_test.cc
+++ b/media/test/pipeline_integration_test.cc
@@ -1229,6 +1229,65 @@
   EXPECT_HASH_EQ("1.30,2.72,4.56,5.08,3.74,2.03,", GetAudioHash());
 }
 
+class Mp3FastSeekParams {
+ public:
+  Mp3FastSeekParams(const char* filename, const char* hash)
+      : filename(filename), hash(hash) {}
+  const char* filename;
+  const char* hash;
+};
+
+class Mp3FastSeekIntegrationTest
+    : public PipelineIntegrationTest,
+      public testing::WithParamInterface<Mp3FastSeekParams> {};
+
+TEST_P(Mp3FastSeekIntegrationTest, FastSeekAccuracy_MP3) {
+  Mp3FastSeekParams config = GetParam();
+  ASSERT_EQ(PIPELINE_OK, Start(config.filename, kHashed));
+
+  // The XING TOC is inaccurate. We don't use it for CBR, we tolerate it for VBR
+  // (best option for fast seeking; see Mp3SeekFFmpegDemuxerTest). The chosen
+  // seek time exposes inaccuracy in TOC such that the hash will change if seek
+  // logic is regressed. See https://crbug.com/545914.
+  //
+  // Quick TOC design (not pretty!):
+  // - All MP3 TOCs are 100 bytes
+  // - Each byte is read as a uint8; value between 0 - 255.
+  // - The index into this array is the numerator in the ratio: index / 100.
+  //   This fraction represents a playback time as a percentage of duration.
+  // - The value at the given index is the numerator in the ratio: value / 256.
+  //   This fraction represents a byte offset as a percentage of the file size.
+  //
+  // For CBR files, each frame is the same size, so the offset for time of
+  // (0.98 * duration) should be around (0.98 * file size). This is 250.88 / 256
+  // but the numerator will be truncated in the TOC as 250, losing precision.
+  base::TimeDelta seek_time(0.98 * pipeline_->GetMediaDuration());
+
+  ASSERT_TRUE(Seek(seek_time));
+  Play();
+  ASSERT_TRUE(WaitUntilOnEnded());
+
+  EXPECT_HASH_EQ(config.hash, GetAudioHash());
+}
+
+// CBR seeks should always be fast and accurate.
+INSTANTIATE_TEST_CASE_P(
+    CBRSeeks,
+    Mp3FastSeekIntegrationTest,
+    ::testing::Values(Mp3FastSeekParams("bear-audio-10s-CBR-has-TOC.mp3",
+                                        "-0.71,0.36,2.96,2.68,2.10,-1.08,"),
+                      Mp3FastSeekParams("bear-audio-10s-CBR-no-TOC.mp3",
+                                        "0.95,0.56,1.34,0.47,1.77,0.84,")));
+
+// VBR seeks can be fast *OR* accurate, but not both. We chose fast.
+INSTANTIATE_TEST_CASE_P(
+    VBRSeeks,
+    Mp3FastSeekIntegrationTest,
+    ::testing::Values(Mp3FastSeekParams("bear-audio-10s-VBR-has-TOC.mp3",
+                                        "-0.15,-0.83,0.54,1.00,1.94,0.93,"),
+                      Mp3FastSeekParams("bear-audio-10s-VBR-no-TOC.mp3",
+                                        "-0.22,0.80,1.19,0.73,-0.31,-1.12,")));
+
 TEST_F(PipelineIntegrationTest, MediaSource_MP3) {
   MockMediaSource source("sfx.mp3", kMP3, kAppendWholeFile);
   StartHashedPipelineWithMediaSource(&source);
diff --git a/media/video/mock_video_decode_accelerator.h b/media/video/mock_video_decode_accelerator.h
index f8bb6da8..87a5953 100644
--- a/media/video/mock_video_decode_accelerator.h
+++ b/media/video/mock_video_decode_accelerator.h
@@ -24,7 +24,7 @@
   MockVideoDecodeAccelerator();
   virtual ~MockVideoDecodeAccelerator();
 
-  MOCK_METHOD2(Initialize, bool(VideoCodecProfile profile, Client* client));
+  MOCK_METHOD2(Initialize, bool(const Config& config, Client* client));
   MOCK_METHOD1(Decode, void(const BitstreamBuffer& bitstream_buffer));
   MOCK_METHOD1(AssignPictureBuffers,
                void(const std::vector<PictureBuffer>& buffers));
diff --git a/media/video/video_decode_accelerator.cc b/media/video/video_decode_accelerator.cc
index 7449a2ae..d1df010 100644
--- a/media/video/video_decode_accelerator.cc
+++ b/media/video/video_decode_accelerator.cc
@@ -9,6 +9,14 @@
 
 namespace media {
 
+VideoDecodeAccelerator::Config::Config(VideoCodecProfile video_codec_profile)
+    : profile(video_codec_profile) {}
+
+VideoDecodeAccelerator::Config::Config(
+    const VideoDecoderConfig& video_decoder_config)
+    : profile(video_decoder_config.profile()),
+      is_encrypted(video_decoder_config.is_encrypted()) {}
+
 void VideoDecodeAccelerator::Client::NotifyCdmAttached(bool success) {
   NOTREACHED() << "By default CDM is not supported.";
 }
diff --git a/media/video/video_decode_accelerator.h b/media/video/video_decode_accelerator.h
index e2bcdf6..da184ee 100644
--- a/media/video/video_decode_accelerator.h
+++ b/media/video/video_decode_accelerator.h
@@ -53,6 +53,19 @@
     LARGEST_ERROR_ENUM,
   };
 
+  // Config structure contains parameters required for the VDA initialization.
+  struct MEDIA_EXPORT Config {
+    Config() = default;
+    Config(VideoCodecProfile profile);
+    Config(const VideoDecoderConfig& video_decoder_config);
+
+    // |profile| combines the information about the codec and its profile.
+    VideoCodecProfile profile = VIDEO_CODEC_PROFILE_UNKNOWN;
+
+    // The flag indicating whether the stream is encrypted.
+    bool is_encrypted = false;
+  };
+
   // Interface for collaborating with picture interface to provide memory for
   // output picture and blitting them. These callbacks will not be made unless
   // Initialize() has returned successfully.
@@ -111,10 +124,10 @@
   // attached can we start to decode.
   //
   // Parameters:
-  //  |profile| is the video stream's format profile.
+  //  |config| contains the initialization parameters.
   //  |client| is the client of this video decoder. Does not take ownership of
   //  |client| which must be valid until Destroy() is called.
-  virtual bool Initialize(VideoCodecProfile profile, Client* client) = 0;
+  virtual bool Initialize(const Config& config, Client* client) = 0;
 
   // Sets a CDM to be used by the decoder to decode encrypted buffers.
   // Client::NotifyCdmAttached() will then be called to indicate whether the CDM
diff --git a/mojo/converters/blink/BUILD.gn b/mojo/converters/blink/BUILD.gn
new file mode 100644
index 0000000..f5486f05
--- /dev/null
+++ b/mojo/converters/blink/BUILD.gn
@@ -0,0 +1,24 @@
+# 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.
+
+component("blink") {
+  output_name = "mojo_blink_lib"
+
+  sources = [
+    "blink_input_events_type_converters.cc",
+    "blink_input_events_type_converters.h",
+    "mojo_blink_export.h",
+  ]
+
+  defines = [ "MOJO_CONVERTERS_BLINK_IMPLEMENTATION" ]
+
+  deps = [
+    "//base",
+    "//components/mus/public/interfaces",
+    "//mojo/environment:chromium",
+    "//mojo/public/c/system:for_component",
+    "//third_party/WebKit/public:blink",
+    "//ui/events",
+  ]
+}
diff --git a/mojo/converters/blink/DEPS b/mojo/converters/blink/DEPS
new file mode 100644
index 0000000..95de851
--- /dev/null
+++ b/mojo/converters/blink/DEPS
@@ -0,0 +1,6 @@
+include_rules = [
+  "+base",
+  "+components/mus/public",
+  "+third_party/WebKit/public",
+  "+ui/events"
+]
diff --git a/components/html_viewer/blink_input_events_type_converters.cc b/mojo/converters/blink/blink_input_events_type_converters.cc
similarity index 96%
rename from components/html_viewer/blink_input_events_type_converters.cc
rename to mojo/converters/blink/blink_input_events_type_converters.cc
index 5b36a77..eca9fac 100644
--- a/components/html_viewer/blink_input_events_type_converters.cc
+++ b/mojo/converters/blink/blink_input_events_type_converters.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/html_viewer/blink_input_events_type_converters.h"
+#include "mojo/converters/blink/blink_input_events_type_converters.h"
 
 #include "base/logging.h"
 #include "base/time/time.h"
@@ -117,8 +117,9 @@
 
   switch (event->action) {
     case mus::mojom::EVENT_TYPE_KEY_PRESSED:
-      web_event->type = event->key_data->is_char ? blink::WebInputEvent::Char :
-          blink::WebInputEvent::RawKeyDown;
+      web_event->type = event->key_data->is_char
+                            ? blink::WebInputEvent::Char
+                            : blink::WebInputEvent::RawKeyDown;
       break;
     case mus::mojom::EVENT_TYPE_KEY_RELEASED:
       web_event->type = blink::WebInputEvent::KeyUp;
@@ -204,7 +205,8 @@
       if (event->pointer_data &&
           event->pointer_data->kind == mus::mojom::POINTER_KIND_MOUSE) {
         return BuildWebMouseEventFrom(event);
-    }
+      }
+      return nullptr;
     case mus::mojom::EVENT_TYPE_WHEEL:
       return BuildWebMouseWheelEventFrom(event);
     case mus::mojom::EVENT_TYPE_KEY_PRESSED:
diff --git a/mojo/converters/blink/blink_input_events_type_converters.h b/mojo/converters/blink/blink_input_events_type_converters.h
new file mode 100644
index 0000000..bb1dce1
--- /dev/null
+++ b/mojo/converters/blink/blink_input_events_type_converters.h
@@ -0,0 +1,27 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MOJO_CONVERTERS_BLINK_BLINK_INPUT_EVENTS_TYPE_CONVERTERS_H_
+#define MOJO_CONVERTERS_BLINK_BLINK_INPUT_EVENTS_TYPE_CONVERTERS_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "components/mus/public/interfaces/input_events.mojom.h"
+#include "mojo/converters/blink/mojo_blink_export.h"
+
+namespace blink {
+class WebInputEvent;
+}
+
+namespace mojo {
+
+template <>
+struct MOJO_BLINK_EXPORT
+    TypeConverter<scoped_ptr<blink::WebInputEvent>, mus::mojom::EventPtr> {
+  static scoped_ptr<blink::WebInputEvent> Convert(
+      const mus::mojom::EventPtr& input);
+};
+
+}  // namespace mojo
+
+#endif  // MOJO_CONVERTERS_BLINK_BLINK_INPUT_EVENTS_TYPE_CONVERTERS_H_
diff --git a/mojo/converters/blink/mojo_blink_export.h b/mojo/converters/blink/mojo_blink_export.h
new file mode 100644
index 0000000..1a77184
--- /dev/null
+++ b/mojo/converters/blink/mojo_blink_export.h
@@ -0,0 +1,32 @@
+// 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.
+
+#ifndef MOJO_CONVERTERS_BLINK_MOJO_BLINK_EXPORT_H_
+#define MOJO_CONVERTERS_BLINK_MOJO_BLINK_EXPORT_H_
+
+#if defined(COMPONENT_BUILD)
+
+#if defined(WIN32)
+
+#if defined(MOJO_CONVERTERS_BLINK_IMPLEMENTATION)
+#define MOJO_BLINK_EXPORT __declspec(dllexport)
+#else
+#define MOJO_BLINK_EXPORT __declspec(dllimport)
+#endif
+
+#else  // !defined(WIN32)
+
+#if defined(MOJO_CONVERTERS_BLINK_IMPLEMENTATION)
+#define MOJO_BLINK_EXPORT __attribute__((visibility("default")))
+#else
+#define MOJO_BLINK_EXPORT
+#endif
+
+#endif  // defined(WIN32)
+
+#else  // !defined(COMPONENT_BUILD)
+#define MOJO_BLINK_EXPORT
+#endif
+
+#endif  // MOJO_CONVERTERS_BLINK_MOJO_BLINK_EXPORT_H_
diff --git a/mojo/edk/embedder/embedder.cc b/mojo/edk/embedder/embedder.cc
index f9b5c9daa..eb572c57 100644
--- a/mojo/edk/embedder/embedder.cc
+++ b/mojo/edk/embedder/embedder.cc
@@ -28,25 +28,10 @@
 namespace mojo {
 namespace edk {
 
-// TODO(jam): move into annonymous namespace. Keep outside for debugging in VS
-// temporarily.
-int g_channel_count = 0;
-bool g_wait_for_no_more_channels = false;
-base::TaskRunner* g_delegate_task_runner = nullptr;  // Used at shutdown.
-
 namespace {
 
 // Note: Called on the I/O thread.
-void ShutdownIPCSupportHelper(bool wait_for_no_more_channels) {
-  if (wait_for_no_more_channels && g_channel_count) {
-    g_wait_for_no_more_channels = true;
-    return;
-  }
-
-  g_delegate_task_runner->PostTask(
-      FROM_HERE, base::Bind(&ProcessDelegate::OnShutdownComplete,
-                            base::Unretained(internal::g_process_delegate)));
-  g_delegate_task_runner = nullptr;
+void ShutdownIPCSupportHelper() {
 }
 
 }  // namespace
@@ -65,23 +50,6 @@
   return g_core;
 }
 
-void ChannelStarted() {
-  DCHECK(g_io_thread_task_runner->RunsTasksOnCurrentThread());
-  g_channel_count++;
-}
-
-void ChannelShutdown() {
-  DCHECK(g_io_thread_task_runner->RunsTasksOnCurrentThread());
-  DCHECK_GT(g_channel_count, 0);
-  g_channel_count--;
-  if (!g_channel_count && g_wait_for_no_more_channels) {
-    // Reset g_wait_for_no_more_channels for unit tests which initialize and
-    // tear down multiple times in a process.
-    g_wait_for_no_more_channels = false;
-    ShutdownIPCSupportHelper(false);
-  }
-}
-
 }  // namespace internal
 
 void SetMaxMessageSize(size_t bytes) {
@@ -188,15 +156,11 @@
 }
 
 void ShutdownIPCSupport() {
-  g_delegate_task_runner = base::MessageLoop::current()->task_runner().get();
-  internal::g_io_thread_task_runner->PostTask(
-      FROM_HERE, base::Bind(&ShutdownIPCSupportHelper, false));
-}
-
-void ShutdownIPCSupportAndWaitForNoChannels() {
-  g_delegate_task_runner = base::MessageLoop::current()->task_runner().get();
-  internal::g_io_thread_task_runner->PostTask(
-      FROM_HERE, base::Bind(&ShutdownIPCSupportHelper, true));
+  internal::g_io_thread_task_runner->PostTaskAndReply(
+      FROM_HERE,
+      base::Bind(&ShutdownIPCSupportHelper),
+      base::Bind(&ProcessDelegate::OnShutdownComplete,
+                 base::Unretained(internal::g_process_delegate)));
 }
 
 ScopedMessagePipeHandle CreateMessagePipe(
diff --git a/mojo/edk/embedder/embedder.h b/mojo/edk/embedder/embedder.h
index 5ba2449..a96c610 100644
--- a/mojo/edk/embedder/embedder.h
+++ b/mojo/edk/embedder/embedder.h
@@ -115,11 +115,6 @@
 // |OnShutdownComplete()|.
 MOJO_SYSTEM_IMPL_EXPORT void ShutdownIPCSupport();
 
-// Like above, but doesn't call |OnShutdownComplete| until all channels are
-// gone.
-// TODO(jam): this should be the default behavior.
-MOJO_SYSTEM_IMPL_EXPORT void ShutdownIPCSupportAndWaitForNoChannels();
-
 // Creates a message pipe from a platform handle. Safe to call from any thread.
 MOJO_SYSTEM_IMPL_EXPORT ScopedMessagePipeHandle
 CreateMessagePipe(ScopedPlatformHandle platform_handle);
diff --git a/mojo/edk/embedder/embedder_internal.h b/mojo/edk/embedder/embedder_internal.h
index 99ea3927..a6fb2b1 100644
--- a/mojo/edk/embedder/embedder_internal.h
+++ b/mojo/edk/embedder/embedder_internal.h
@@ -43,9 +43,6 @@
 // TODO(use_chrome_edk): temporary until we have only one SDK.
 MOJO_SYSTEM_IMPL_EXPORT Core* GetCore();
 
-// Called on the IO thread.
-void ChannelStarted();
-void ChannelShutdown();
 }  // namespace internal
 
 }  // namepace edk
diff --git a/mojo/edk/system/multiprocess_message_pipe_unittest.cc b/mojo/edk/system/multiprocess_message_pipe_unittest.cc
index 4abac12..4bb3f133 100644
--- a/mojo/edk/system/multiprocess_message_pipe_unittest.cc
+++ b/mojo/edk/system/multiprocess_message_pipe_unittest.cc
@@ -166,12 +166,6 @@
                              nullptr, 0u, MOJO_WRITE_MESSAGE_FLAG_NONE));
   }
 
-  const std::string quitquitquit("quitquitquit");
-  ASSERT_EQ(MOJO_RESULT_OK,
-            MojoWriteMessage(mp.get().value(), quitquitquit.data(),
-                             static_cast<uint32_t>(quitquitquit.size()),
-                             nullptr, 0u, MOJO_WRITE_MESSAGE_FLAG_NONE));
-
   for (size_t i = 0; i < kNumMessages; i++) {
     HandleSignalsState hss;
     ASSERT_EQ(MOJO_RESULT_OK,
@@ -194,6 +188,12 @@
     ASSERT_EQ(std::string(i * 2, 'A' + (i % 26)), read_buffer);
   }
 
+  const std::string quitquitquit("quitquitquit");
+  ASSERT_EQ(MOJO_RESULT_OK,
+            MojoWriteMessage(mp.get().value(), quitquitquit.data(),
+                             static_cast<uint32_t>(quitquitquit.size()),
+                             nullptr, 0u, MOJO_WRITE_MESSAGE_FLAG_NONE));
+
   // Wait for it to become readable, which should fail (since we sent
   // "quitquitquit").
   HandleSignalsState hss;
diff --git a/mojo/edk/system/raw_channel.cc b/mojo/edk/system/raw_channel.cc
index a7faead..b60438e 100644
--- a/mojo/edk/system/raw_channel.cc
+++ b/mojo/edk/system/raw_channel.cc
@@ -221,7 +221,6 @@
   if (initialized_)
     return;
   initialized_ = true;
-  internal::ChannelStarted();
   base::MessageLoop::current()->AddDestructionObserver(this);
 
   OnInit();
@@ -288,7 +287,6 @@
     }
 
     if (initialized_) {
-      internal::ChannelShutdown();
       base::MessageLoop::current()->RemoveDestructionObserver(this);
     }
     delete this;
diff --git a/mojo/edk/system/raw_channel_win.cc b/mojo/edk/system/raw_channel_win.cc
index fa968a4..51a8e684 100644
--- a/mojo/edk/system/raw_channel_win.cc
+++ b/mojo/edk/system/raw_channel_win.cc
@@ -124,6 +124,7 @@
     RawChannelIOHandler(RawChannelWin* owner,
                         ScopedPlatformHandle handle)
         : handle_(handle.Pass()),
+          io_task_runner_(internal::g_io_thread_task_runner),
           owner_(owner),
           suppress_self_destruct_(false),
           pending_read_(false),
@@ -465,7 +466,7 @@
       // that that is always a pointer to a valid RawChannelIOHandler.
       RawChannelIOHandler* that = static_cast<RawChannelIOHandler*>(param);
       that->read_event_signalled_ = true;
-      internal::g_io_thread_task_runner->PostTask(
+      that->io_task_runner_->PostTask(
           FROM_HERE,
           base::Bind(&RawChannelIOHandler::OnObjectSignaled,
                      that->this_weakptr_, that->read_event_.Get()));
@@ -477,7 +478,7 @@
       // that that is always a pointer to a valid RawChannelIOHandler.
       RawChannelIOHandler* that = static_cast<RawChannelIOHandler*>(param);
       that->write_event_signalled_ = true;
-      internal::g_io_thread_task_runner->PostTask(
+      that->io_task_runner_->PostTask(
           FROM_HERE,
           base::Bind(&RawChannelIOHandler::OnObjectSignaled,
                      that->this_weakptr_, that->write_event_.Get()));
@@ -485,6 +486,10 @@
 
     ScopedPlatformHandle handle_;
 
+    // We cache this because ReadCompleted and WriteCompleted might get fired
+    // after ShutdownIPCSupport is called.
+    scoped_refptr<base::TaskRunner> io_task_runner_;
+
     // |owner_| is reset on the I/O thread under |owner_->write_lock()|.
     // Therefore, it may be used on any thread under lock; or on the I/O thread
     // without locking.
diff --git a/mojo/edk/system/run_all_unittests.cc b/mojo/edk/system/run_all_unittests.cc
index 71e1465..b68fd83 100644
--- a/mojo/edk/system/run_all_unittests.cc
+++ b/mojo/edk/system/run_all_unittests.cc
@@ -26,10 +26,11 @@
     mojo::edk::PreInitializeChildProcess();
   }
 
-  mojo::edk::Init();
   // TODO(use_chrome_edk): temporary to force new EDK.
   base::CommandLine::ForCurrentProcess()->AppendSwitch("--use-new-edk");
 
+  mojo::edk::Init();
+
   return base::LaunchUnitTests(
       argc, argv,
       base::Bind(&base::TestSuite::Run, base::Unretained(&test_suite)));
diff --git a/mojo/edk/system/shared_buffer_dispatcher.cc b/mojo/edk/system/shared_buffer_dispatcher.cc
index 1f15ea2..85732cf 100644
--- a/mojo/edk/system/shared_buffer_dispatcher.cc
+++ b/mojo/edk/system/shared_buffer_dispatcher.cc
@@ -5,6 +5,7 @@
 #include "mojo/edk/system/shared_buffer_dispatcher.h"
 
 #include <limits>
+#include <utility>
 
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
@@ -76,7 +77,7 @@
   if (!shared_buffer)
     return MOJO_RESULT_RESOURCE_EXHAUSTED;
 
-  *result = CreateInternal(shared_buffer.Pass());
+  *result = CreateInternal(std::move(shared_buffer));
   return MOJO_RESULT_OK;
 }
 
@@ -129,7 +130,7 @@
     return nullptr;
   }
 
-  return CreateInternal(shared_buffer.Pass());
+  return CreateInternal(std::move(shared_buffer));
 }
 
 SharedBufferDispatcher::SharedBufferDispatcher(
@@ -183,7 +184,7 @@
 SharedBufferDispatcher::CreateEquivalentDispatcherAndCloseImplNoLock() {
   lock().AssertAcquired();
   DCHECK(shared_buffer_);
-  return CreateInternal(shared_buffer_.Pass());
+  return CreateInternal(std::move(shared_buffer_));
 }
 
 MojoResult SharedBufferDispatcher::DuplicateBufferHandleImplNoLock(
diff --git a/mojo/edk/system/shared_buffer_dispatcher.h b/mojo/edk/system/shared_buffer_dispatcher.h
index f3fc9e80c..90755603 100644
--- a/mojo/edk/system/shared_buffer_dispatcher.h
+++ b/mojo/edk/system/shared_buffer_dispatcher.h
@@ -5,6 +5,8 @@
 #ifndef MOJO_EDK_SYSTEM_SHARED_BUFFER_DISPATCHER_H_
 #define MOJO_EDK_SYSTEM_SHARED_BUFFER_DISPATCHER_H_
 
+#include <utility>
+
 #include "mojo/edk/embedder/platform_shared_buffer.h"
 #include "mojo/edk/system/simple_dispatcher.h"
 #include "mojo/edk/system/system_impl_export.h"
@@ -58,7 +60,8 @@
  private:
   static scoped_refptr<SharedBufferDispatcher> CreateInternal(
       scoped_refptr<PlatformSharedBuffer> shared_buffer) {
-    return make_scoped_refptr(new SharedBufferDispatcher(shared_buffer.Pass()));
+    return make_scoped_refptr(
+        new SharedBufferDispatcher(std::move(shared_buffer)));
   }
 
   explicit SharedBufferDispatcher(
diff --git a/mojo/edk/test/scoped_ipc_support.cc b/mojo/edk/test/scoped_ipc_support.cc
index 6e9c11c..68e7ac2fa 100644
--- a/mojo/edk/test/scoped_ipc_support.cc
+++ b/mojo/edk/test/scoped_ipc_support.cc
@@ -4,6 +4,8 @@
 
 #include "mojo/edk/test/scoped_ipc_support.h"
 
+#include <utility>
+
 #include "base/message_loop/message_loop.h"
 #include "mojo/edk/embedder/embedder.h"
 
@@ -21,7 +23,7 @@
       base::MessageLoop::current()->task_runner() == io_thread_task_runner_) {
     ShutdownIPCSupportOnIOThread();
   } else {
-    ShutdownIPCSupportAndWaitForNoChannels();
+    ShutdownIPCSupport();
     run_loop_.Run();
   }
 }
@@ -41,7 +43,7 @@
 
 ScopedIPCSupport::ScopedIPCSupport(
     scoped_refptr<base::TaskRunner> io_thread_task_runner) {
-  helper_.Init(this, io_thread_task_runner.Pass());
+  helper_.Init(this, std::move(io_thread_task_runner));
 }
 
 ScopedIPCSupport::~ScopedIPCSupport() {
diff --git a/mojo/generate_mojo_shell_assets_list.gni b/mojo/generate_mojo_shell_assets_list.gni
deleted file mode 100644
index a8c7cb8..0000000
--- a/mojo/generate_mojo_shell_assets_list.gni
+++ /dev/null
@@ -1,25 +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.
-
-# Used to generate an assets_list file. To use supply the argument 'dir', which
-# is where the assets can be found.
-# TODO(sky): Perhaps combine this with the copy step?
-template("generate_mojo_shell_assets_list") {
-  action(target_name) {
-    script = "//mojo/tools/generate_mojo_shell_assets_list.py"
-    args = [
-      "--dir",
-      rebase_path(invoker.dir, root_build_dir),
-    ]
-    outputs = [
-      invoker.dir + "/assets_list",
-    ]
-    if (defined(invoker.deps)) {
-      deps = invoker.deps
-    }
-    if (defined(invoker.testonly)) {
-      testonly = invoker.testonly
-    }
-  }
-}
diff --git a/mojo/gpu/mojo_gles2_impl_autogen.cc b/mojo/gpu/mojo_gles2_impl_autogen.cc
index 8f817e3b..2b2538a 100644
--- a/mojo/gpu/mojo_gles2_impl_autogen.cc
+++ b/mojo/gpu/mojo_gles2_impl_autogen.cc
@@ -1909,5 +1909,22 @@
   MojoGLES2MakeCurrent(context_);
   glApplyScreenSpaceAntialiasingCHROMIUM();
 }
+void MojoGLES2Impl::BindFragDataLocationIndexedEXT(GLuint program,
+                                                   GLuint colorNumber,
+                                                   GLuint index,
+                                                   const char* name) {
+  MojoGLES2MakeCurrent(context_);
+  glBindFragDataLocationIndexedEXT(program, colorNumber, index, name);
+}
+void MojoGLES2Impl::BindFragDataLocationEXT(GLuint program,
+                                            GLuint colorNumber,
+                                            const char* name) {
+  MojoGLES2MakeCurrent(context_);
+  glBindFragDataLocationEXT(program, colorNumber, name);
+}
+GLint MojoGLES2Impl::GetFragDataIndexEXT(GLuint program, const char* name) {
+  MojoGLES2MakeCurrent(context_);
+  return glGetFragDataIndexEXT(program, name);
+}
 
 }  // namespace mojo
diff --git a/mojo/gpu/mojo_gles2_impl_autogen.h b/mojo/gpu/mojo_gles2_impl_autogen.h
index e207ca49..c00372dd 100644
--- a/mojo/gpu/mojo_gles2_impl_autogen.h
+++ b/mojo/gpu/mojo_gles2_impl_autogen.h
@@ -888,6 +888,14 @@
   GLenum GetGraphicsResetStatusKHR() override;
   void BlendBarrierKHR() override;
   void ApplyScreenSpaceAntialiasingCHROMIUM() override;
+  void BindFragDataLocationIndexedEXT(GLuint program,
+                                      GLuint colorNumber,
+                                      GLuint index,
+                                      const char* name) override;
+  void BindFragDataLocationEXT(GLuint program,
+                               GLuint colorNumber,
+                               const char* name) override;
+  GLint GetFragDataIndexEXT(GLuint program, const char* name) override;
 
  private:
   MojoGLES2Context context_;
diff --git a/mojo/public/c/gles2/gles2_call_visitor_chromium_extension_autogen.h b/mojo/public/c/gles2/gles2_call_visitor_chromium_extension_autogen.h
index a6c8585..c0668d3c 100644
--- a/mojo/public/c/gles2/gles2_call_visitor_chromium_extension_autogen.h
+++ b/mojo/public/c/gles2/gles2_call_visitor_chromium_extension_autogen.h
@@ -568,3 +568,16 @@
 VISIT_GL_CALL(GetGraphicsResetStatusKHR, GLenum, (), ())
 VISIT_GL_CALL(BlendBarrierKHR, void, (), ())
 VISIT_GL_CALL(ApplyScreenSpaceAntialiasingCHROMIUM, void, (), ())
+VISIT_GL_CALL(
+    BindFragDataLocationIndexedEXT,
+    void,
+    (GLuint program, GLuint colorNumber, GLuint index, const char* name),
+    (program, colorNumber, index, name))
+VISIT_GL_CALL(BindFragDataLocationEXT,
+              void,
+              (GLuint program, GLuint colorNumber, const char* name),
+              (program, colorNumber, name))
+VISIT_GL_CALL(GetFragDataIndexEXT,
+              GLint,
+              (GLuint program, const char* name),
+              (program, name))
diff --git a/mojo/public/cpp/bindings/lib/bindings_serialization.cc b/mojo/public/cpp/bindings/lib/bindings_serialization.cc
index 22733c26..d9ced4c3 100644
--- a/mojo/public/cpp/bindings/lib/bindings_serialization.cc
+++ b/mojo/public/cpp/bindings/lib/bindings_serialization.cc
@@ -90,7 +90,7 @@
 
 SerializationContext::SerializationContext(
     scoped_refptr<MultiplexRouter> in_router)
-    : router(in_router.Pass()) {}
+    : router(std::move(in_router)) {}
 
 SerializationContext::~SerializationContext() {}
 
diff --git a/mojo/public/cpp/bindings/lib/multiplex_router.cc b/mojo/public/cpp/bindings/lib/multiplex_router.cc
index c09fc17..69defac 100644
--- a/mojo/public/cpp/bindings/lib/multiplex_router.cc
+++ b/mojo/public/cpp/bindings/lib/multiplex_router.cc
@@ -4,6 +4,8 @@
 
 #include "mojo/public/cpp/bindings/lib/multiplex_router.h"
 
+#include <utility>
+
 #include "base/bind.h"
 #include "base/message_loop/message_loop.h"
 #include "base/stl_util.h"
@@ -49,7 +51,7 @@
   void set_task_runner(
       scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
     router_lock_->AssertAcquired();
-    task_runner_ = task_runner.Pass();
+    task_runner_ = std::move(task_runner);
   }
 
   InterfaceEndpointClient* client() const { return client_; }
diff --git a/mojo/public/cpp/bindings/lib/scoped_interface_endpoint_handle.cc b/mojo/public/cpp/bindings/lib/scoped_interface_endpoint_handle.cc
index 6f30c94..dfe4e234 100644
--- a/mojo/public/cpp/bindings/lib/scoped_interface_endpoint_handle.cc
+++ b/mojo/public/cpp/bindings/lib/scoped_interface_endpoint_handle.cc
@@ -17,7 +17,7 @@
     InterfaceId id,
     bool is_local,
     scoped_refptr<MultiplexRouter> router)
-    : id_(id), is_local_(is_local), router_(router.Pass()) {
+    : id_(id), is_local_(is_local), router_(std::move(router)) {
   DCHECK(!IsValidInterfaceId(id) || router_);
 }
 
diff --git a/mojo/public/cpp/bindings/lib/scoped_interface_endpoint_handle.h b/mojo/public/cpp/bindings/lib/scoped_interface_endpoint_handle.h
index 09ee7ca7..c4527d0 100644
--- a/mojo/public/cpp/bindings/lib/scoped_interface_endpoint_handle.h
+++ b/mojo/public/cpp/bindings/lib/scoped_interface_endpoint_handle.h
@@ -7,6 +7,7 @@
 
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
+#include "base/move.h"
 #include "mojo/public/cpp/bindings/lib/interface_id.h"
 
 namespace mojo {
diff --git a/mojo/public/cpp/system/macros.h b/mojo/public/cpp/system/macros.h
index 7f0fcd7..b565f12 100644
--- a/mojo/public/cpp/system/macros.h
+++ b/mojo/public/cpp/system/macros.h
@@ -35,8 +35,8 @@
 // to tell that this type is move-only.
 #define MOJO_MOVE_ONLY_TYPE(type)                                              \
  private:                                                                      \
-  type(type&);                                                                 \
-  void operator=(type&);                                                       \
+  type(const type&) = delete;                                                  \
+  void operator=(const type&) = delete;                                        \
                                                                                \
  public:                                                                       \
   type&& Pass() MOJO_WARN_UNUSED_RESULT { return static_cast<type&&>(*this); } \
diff --git a/mojo/public/java/BUILD.gn b/mojo/public/java/BUILD.gn
index d543394a..dd819cf 100644
--- a/mojo/public/java/BUILD.gn
+++ b/mojo/public/java/BUILD.gn
@@ -25,6 +25,8 @@
 
 android_library("bindings") {
   java_files = [
+    "bindings/src/org/chromium/mojo/bindings/AssociatedInterfaceNotSupported.java",
+    "bindings/src/org/chromium/mojo/bindings/AssociatedInterfaceRequestNotSupported.java",
     "bindings/src/org/chromium/mojo/bindings/AutoCloseableRouter.java",
     "bindings/src/org/chromium/mojo/bindings/BindingsHelper.java",
     "bindings/src/org/chromium/mojo/bindings/Callbacks.java",
diff --git a/mojo/public/java/bindings/src/org/chromium/mojo/bindings/AssociatedInterfaceNotSupported.java b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/AssociatedInterfaceNotSupported.java
new file mode 100644
index 0000000..ee8f631
--- /dev/null
+++ b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/AssociatedInterfaceNotSupported.java
@@ -0,0 +1,11 @@
+// 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.mojo.bindings;
+
+/**
+ * Associated interface is not supported yet.
+ */
+public class AssociatedInterfaceNotSupported {
+}
diff --git a/mojo/public/java/bindings/src/org/chromium/mojo/bindings/AssociatedInterfaceRequestNotSupported.java b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/AssociatedInterfaceRequestNotSupported.java
new file mode 100644
index 0000000..1b07cd1
--- /dev/null
+++ b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/AssociatedInterfaceRequestNotSupported.java
@@ -0,0 +1,11 @@
+// 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.mojo.bindings;
+
+/**
+ * Associated interface is not supported yet.
+ */
+public class AssociatedInterfaceRequestNotSupported {
+}
diff --git a/mojo/public/java/bindings/src/org/chromium/mojo/bindings/Decoder.java b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/Decoder.java
index 868eab6..6e4eba6 100644
--- a/mojo/public/java/bindings/src/org/chromium/mojo/bindings/Decoder.java
+++ b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/Decoder.java
@@ -494,6 +494,22 @@
     }
 
     /**
+     * Deserializes an associated interface at the given offset. Not yet supported.
+     */
+    public AssociatedInterfaceNotSupported readAssociatedServiceInterfaceNotSupported(int offset,
+            boolean nullable) {
+        return null;
+    }
+
+    /**
+     * Deserializes an associated interface request at the given offset. Not yet supported.
+     */
+    public AssociatedInterfaceRequestNotSupported readAssociatedInterfaceRequestNotSupported(
+            int offset, boolean nullable) {
+        return null;
+    }
+
+    /**
      * Deserializes a string at the given offset.
      */
     public String readString(int offset, boolean nullable) {
diff --git a/mojo/public/java/bindings/src/org/chromium/mojo/bindings/Encoder.java b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/Encoder.java
index 3541f21..7532736 100644
--- a/mojo/public/java/bindings/src/org/chromium/mojo/bindings/Encoder.java
+++ b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/Encoder.java
@@ -304,6 +304,18 @@
     }
 
     /**
+     * Encode an associated interface. Not yet supported.
+     */
+    public void encode(AssociatedInterfaceNotSupported v, int offset, boolean nullable) {
+    }
+
+    /**
+     * Encode an associated interface request. Not yet supported.
+     */
+    public void encode(AssociatedInterfaceRequestNotSupported v, int offset, boolean nullable) {
+    }
+
+    /**
      * Returns an {@link Encoder} suitable for encoding an array of pointer of the given length.
      */
     public Encoder encodePointerArray(int length, int offset, int expectedLength) {
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/interface_definition.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/interface_definition.tmpl
index 267872a..9889f8b 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/interface_definition.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/interface_definition.tmpl
@@ -16,7 +16,7 @@
 {%- macro pass_params(parameters) %}
 {%-   for param in parameters %}
 {%-     if param.kind|is_move_only_kind -%}
-p_{{param.name}}.Pass()
+std::move(p_{{param.name}})
 {%-     else -%}
 p_{{param.name}}
 {%-     endif -%}
@@ -56,7 +56,7 @@
   {{class_name}}_{{method.name}}_ForwardToCallback(
       const {{class_name}}::{{method.name}}Callback& callback,
       scoped_refptr<mojo::internal::MultiplexRouter> router)
-      : callback_(callback), serialization_context_(router.Pass()) {
+      : callback_(callback), serialization_context_(std::move(router)) {
   }
   bool Accept(mojo::Message* message) override;
  private:
diff --git a/mojo/runner/BUILD.gn b/mojo/runner/BUILD.gn
index 1496e4e..64ba3f87 100644
--- a/mojo/runner/BUILD.gn
+++ b/mojo/runner/BUILD.gn
@@ -2,7 +2,6 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("//mojo/generate_mojo_shell_assets_list.gni")
 import("//mojo/public/mojo_application.gni")
 import("//mojo/public/tools/bindings/mojom.gni")
 import("//testing/test.gni")
@@ -268,12 +267,21 @@
     custom_package = "org.chromium.mojo.shell"
   }
 
-  android_assets("mojo_runner_apptests_assets") {
-    testonly = true
-
+  android_assets("android_assets") {
     deps = [
       ":bootstrap",
       ":bootstrap_java",
+    ]
+    sources = [
+      "$root_out_dir/obj/mojo/runner/bootstrap_java.dex.jar",
+      "$root_shlib_dir/${shlib_prefix}bootstrap$shlib_extension",
+    ]
+  }
+
+  android_assets("mojo_runner_apptests_assets") {
+    testonly = true
+    deps = [
+      ":android_assets",
       "//components/clipboard:apptests_assets",
       "//components/clipboard:clipboard_assets",
       "//components/mus/ws:apptests_assets",
@@ -283,11 +291,6 @@
       "//mojo/services/network:network_assets",
       "//third_party/icu:icu_assets",
     ]
-
-    sources = [
-      "$root_out_dir/obj/mojo/runner/bootstrap_java.dex.jar",
-      "$root_shlib_dir/${shlib_prefix}bootstrap$shlib_extension",
-    ]
   }
 
   copy("copy_mojo_runner") {
diff --git a/mojo/runner/host/BUILD.gn b/mojo/runner/host/BUILD.gn
index 713251e..3bfd5aa 100644
--- a/mojo/runner/host/BUILD.gn
+++ b/mojo/runner/host/BUILD.gn
@@ -2,7 +2,6 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("//mojo/generate_mojo_shell_assets_list.gni")
 import("//mojo/public/mojo_application.gni")
 import("//mojo/public/tools/bindings/mojom.gni")
 import("//testing/test.gni")
diff --git a/mojo/tools/data/apptests b/mojo/tools/data/apptests
index c51c5cf..27b077a 100644
--- a/mojo/tools/data/apptests
+++ b/mojo/tools/data/apptests
@@ -46,7 +46,6 @@
   #  'test': 'mojo:runner_apptests',
   #  'type': 'gtest_isolated',
   #},
-  mus_apptests,
 ]
 
 # TODO(msw): Get these tests passing on Android too. http://crbug.com/486220
@@ -77,18 +76,21 @@
       'test': 'mojo:mandoline_browser_apptests',
       'type': 'gtest_isolated',
     },
-    {
-      'test': 'mojo:mash_wm_apptests',
-      'type': 'gtest_isolated',
-      'args': ['--use-x11-test-config',
-               '--override-use-gl-with-osmesa-for-tests']
-    },
+    # TODO(sky): flakey, http://crbug.com/559412 .
+    # {
+    #   'test': 'mojo:mash_wm_apptests',
+    #   'type': 'gtest_isolated',
+    #   'args': ['--use-x11-test-config',
+    #            '--override-use-gl-with-osmesa-for-tests']
+    # },
     # TODO(xhwang): Fix and enable mojo:media_pipeline_integration_apptests.
     # http://crbug.com/501417
     {
       'test': 'mojo:media_apptests',
       'type': 'gtest_isolated',
     },
+    # TODO(crbug.com/560626): Fix and enable mus_apptests on Android.
+    mus_apptests,
     {
       'test': 'mojo:sql_apptests',
       'type': 'gtest_isolated',
diff --git a/mojo/tools/generate_mojo_shell_assets_list.py b/mojo/tools/generate_mojo_shell_assets_list.py
deleted file mode 100755
index 1018e943..0000000
--- a/mojo/tools/generate_mojo_shell_assets_list.py
+++ /dev/null
@@ -1,46 +0,0 @@
-#!/usr/bin/env python
-#
-# 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.
-
-'''Generates the assets_list file from a directory.'''
-
-import argparse
-import os
-import sys
-
-def main():
-  parser = argparse.ArgumentParser(usage='--dir <directory>')
-
-  parser.add_argument('--dir', help='Directory read files from.', required=True)
-
-  options, _ = parser.parse_known_args()
-
-  if not os.path.exists(options.dir) or not os.path.isdir(options.dir):
-    print 'Directory does not exist, or path is not a directory', options.dir
-    return -1
-
-  root_dir = os.path.abspath(options.dir)
-  all_files = []
-  for current_root, _, files in os.walk(options.dir):
-    current_root_absolute = os.path.abspath(current_root)
-    if len(current_root_absolute) < len(root_dir):
-      print 'unexpected directory', current_root_absolute
-      return -1
-    rel_root = current_root_absolute[len(root_dir):]
-    if len(rel_root) and rel_root.startswith(os.sep):
-      rel_root = rel_root[len(os.sep):]
-    if len(rel_root) and not rel_root.endswith(os.sep):
-      rel_root += os.sep
-    all_files.extend([rel_root + f for f in files])
-
-  with open(os.path.join(options.dir, 'assets_list'), 'w') as f:
-    for a_file in all_files:
-      f.write(a_file + '\n')
-
-  return 0
-
-if __name__ == '__main__':
-  sys.exit(main())
-
diff --git a/net/BUILD.gn b/net/BUILD.gn
index f0081df..8623889 100644
--- a/net/BUILD.gn
+++ b/net/BUILD.gn
@@ -573,6 +573,7 @@
     "cookies/cookie_store_test_callbacks.h",
     "cookies/cookie_store_test_helpers.cc",
     "cookies/cookie_store_test_helpers.h",
+    "cookies/cookie_store_unittest.h",
     "disk_cache/disk_cache_test_base.cc",
     "disk_cache/disk_cache_test_base.h",
     "disk_cache/disk_cache_test_util.cc",
diff --git a/net/base/hash_value.cc b/net/base/hash_value.cc
index 2a751cd2..7f2e479e 100644
--- a/net/base/hash_value.cc
+++ b/net/base/hash_value.cc
@@ -31,6 +31,15 @@
   return memcmp(data, other.data, sizeof(data)) == 0;
 }
 
+HashValue::HashValue(const SHA1HashValue& hash) : HashValue(HASH_VALUE_SHA1) {
+  fingerprint.sha1 = hash;
+}
+
+HashValue::HashValue(const SHA256HashValue& hash)
+    : HashValue(HASH_VALUE_SHA256) {
+  fingerprint.sha256 = hash;
+}
+
 bool HashValue::Equals(const HashValue& other) const {
   if (tag != other.tag)
     return false;
diff --git a/net/base/hash_value.h b/net/base/hash_value.h
index a9e0b63..f2d217f 100644
--- a/net/base/hash_value.h
+++ b/net/base/hash_value.h
@@ -36,6 +36,8 @@
 
 class NET_EXPORT HashValue {
  public:
+  explicit HashValue(const SHA1HashValue& hash);
+  explicit HashValue(const SHA256HashValue& hash);
   explicit HashValue(HashValueTag tag) : tag(tag) {}
   HashValue() : tag(HASH_VALUE_SHA1) {}
 
diff --git a/net/base/ip_address.cc b/net/base/ip_address.cc
new file mode 100644
index 0000000..99078b8
--- /dev/null
+++ b/net/base/ip_address.cc
@@ -0,0 +1,67 @@
+// Copyright (c) 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.
+
+#include "net/base/ip_address.h"
+
+#include "net/base/ip_address_number.h"
+#include "url/gurl.h"
+#include "url/url_canon_ip.h"
+
+namespace net {
+
+const size_t IPAddress::kIPv4AddressSize = 4;
+const size_t IPAddress::kIPv6AddressSize = 16;
+
+IPAddress::IPAddress() {}
+
+IPAddress::~IPAddress() {}
+
+IPAddress::IPAddress(const uint8_t* address, size_t address_len)
+    : ip_address_(address, address + address_len) {}
+
+bool IPAddress::IsIPv4() const {
+  return ip_address_.size() == kIPv4AddressSize;
+}
+
+bool IPAddress::IsIPv6() const {
+  return ip_address_.size() == kIPv6AddressSize;
+}
+
+bool IPAddress::IsReserved() const {
+  return IsIPAddressReserved(ip_address_);
+}
+
+bool IPAddress::IsIPv4Mapped() const {
+  return net::IsIPv4Mapped(ip_address_);
+}
+
+std::string IPAddress::ToString() const {
+  return IPAddressToString(ip_address_);
+}
+
+// static
+bool IPAddress::FromIPLiteral(const base::StringPiece& ip_literal,
+                              IPAddress* ip_address) {
+  std::vector<uint8_t> number;
+  if (!ParseIPLiteralToNumber(ip_literal, &number))
+    return false;
+
+  std::swap(number, ip_address->ip_address_);
+  return true;
+}
+
+bool IPAddress::operator==(const IPAddress& that) const {
+  return ip_address_ == that.ip_address_;
+}
+
+bool IPAddress::operator<(const IPAddress& that) const {
+  // Sort IPv4 before IPv6.
+  if (ip_address_.size() != that.ip_address_.size()) {
+    return ip_address_.size() < that.ip_address_.size();
+  }
+
+  return ip_address_ < that.ip_address_;
+}
+
+}  // namespace net
diff --git a/net/base/ip_address.h b/net/base/ip_address.h
new file mode 100644
index 0000000..37a5ab6
--- /dev/null
+++ b/net/base/ip_address.h
@@ -0,0 +1,71 @@
+// Copyright (c) 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.
+
+#ifndef NET_BASE_IP_ADDRESS_NET_H_
+#define NET_BASE_IP_ADDRESS_NET_H_
+
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/strings/string_piece.h"
+#include "net/base/net_export.h"
+
+namespace net {
+
+class NET_EXPORT IPAddress {
+ public:
+  static const size_t kIPv4AddressSize;
+  static const size_t kIPv6AddressSize;
+
+  // Creates a zero-sized, invalid address.
+  IPAddress();
+
+  // Copies the input address to |ip_address_|. The input is expected to be in
+  // network byte order.
+  IPAddress(const uint8_t* address, size_t address_len);
+  ~IPAddress();
+
+  // Returns true if the IP has |kIPv4AddressSize| elements.
+  bool IsIPv4() const;
+
+  // Returns true if the IP has |kIPv6AddressSize| elements.
+  bool IsIPv6() const;
+
+  // Returns true if an IP address hostname is in a range reserved by the IANA.
+  // Works with both IPv4 and IPv6 addresses, and only compares against a given
+  // protocols's reserved ranges.
+  bool IsReserved() const;
+
+  // Returns true if |ip_address_| is an IPv4-mapped IPv6 address.
+  bool IsIPv4Mapped() const;
+
+  // The size in bytes of |ip_address_|.
+  size_t size() const { return ip_address_.size(); }
+
+  // Returns the canonical string representation of an IP address.
+  // For example: "192.168.0.1" or "::1". The IP address must be
+  // valid, calling this on an invalid address will result in a crash.
+  std::string ToString() const;
+
+  // Parses an IP address literal (either IPv4 or IPv6) to its numeric value.
+  // Returns true on success and fills |ip_address| with the numeric value.
+  static bool FromIPLiteral(const base::StringPiece& ip_literal,
+                            IPAddress* ip_address) WARN_UNUSED_RESULT;
+
+  // Returns the underlying byte vector.
+  const std::vector<uint8_t>& bytes() const { return ip_address_; };
+
+  bool operator==(const IPAddress& that) const;
+  bool operator<(const IPAddress& that) const;
+
+ private:
+  // IPv4 addresses will have length kIPv4AddressSize, whereas IPv6 address
+  // will have length kIPv6AddressSize.
+  std::vector<uint8_t> ip_address_;
+};
+
+}  // namespace net
+
+#endif  // NET_BASE_IP_ADDRESS_NET_H_
diff --git a/net/base/ip_address_number.h b/net/base/ip_address_number.h
index b105875..bce3c980 100644
--- a/net/base/ip_address_number.h
+++ b/net/base/ip_address_number.h
@@ -19,6 +19,10 @@
 // network byte ordering.
 //
 // IPv4 addresses will have length 4, whereas IPv6 address will have length 16.
+//
+// TODO(Martijnc): Remove the IPAddressNumber typedef. New code should use
+// IPAddress instead and existing code should be switched over.
+// https://crbug.com/496258
 typedef std::vector<unsigned char>
     IPAddressNumber;  // This is also duplicated in net_util.h
 typedef std::vector<IPAddressNumber> IPAddressList;
diff --git a/net/base/ip_address_unittest.cc b/net/base/ip_address_unittest.cc
new file mode 100644
index 0000000..d977b22
--- /dev/null
+++ b/net/base/ip_address_unittest.cc
@@ -0,0 +1,134 @@
+// Copyright (c) 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.
+
+#include "net/base/ip_address.h"
+
+#include <vector>
+
+#include "base/strings/string_number_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+
+namespace {
+
+// Helper to stringize an IP number (used to define expectations).
+std::string DumpIPAddress(const IPAddress& v) {
+  std::string out;
+  for (size_t i = 0; i < v.bytes().size(); ++i) {
+    if (i != 0)
+      out.append(",");
+    out.append(base::UintToString(v.bytes()[i]));
+  }
+  return out;
+}
+
+template <size_t N>
+IPAddress ArrayToIPAdress(const uint8_t(&address)[N]) {
+  return IPAddress(address, N);
+}
+
+TEST(IPAddressTest, IsIPVersion) {
+  uint8_t addr1[4] = {192, 168, 0, 1};
+  IPAddress ip_address1 = ArrayToIPAdress(addr1);
+  EXPECT_TRUE(ip_address1.IsIPv4());
+  EXPECT_FALSE(ip_address1.IsIPv6());
+
+  uint8_t addr2[16] = {0xFE, 0xDC, 0xBA, 0x98};
+  IPAddress ip_address2 = ArrayToIPAdress(addr2);
+  EXPECT_TRUE(ip_address2.IsIPv6());
+  EXPECT_FALSE(ip_address2.IsIPv4());
+
+  IPAddress ip_address3 = IPAddress();
+  EXPECT_FALSE(ip_address3.IsIPv6());
+  EXPECT_FALSE(ip_address3.IsIPv4());
+}
+
+TEST(IPAddressTest, ToString) {
+  uint8_t addr1[4] = {0, 0, 0, 0};
+  IPAddress ip_address1 = ArrayToIPAdress(addr1);
+  EXPECT_EQ("0.0.0.0", ip_address1.ToString());
+
+  uint8_t addr2[4] = {192, 168, 0, 1};
+  IPAddress ip_address2 = ArrayToIPAdress(addr2);
+  EXPECT_EQ("192.168.0.1", ip_address2.ToString());
+
+  uint8_t addr3[16] = {0xFE, 0xDC, 0xBA, 0x98};
+  IPAddress ip_address3 = ArrayToIPAdress(addr3);
+  EXPECT_EQ("fedc:ba98::", ip_address3.ToString());
+}
+
+// Test that invalid IP literals fail to parse.
+TEST(IPAddressTest, FromIPLiteral_FailParse) {
+  IPAddress address;
+
+  EXPECT_FALSE(IPAddress::FromIPLiteral("bad value", &address));
+  EXPECT_FALSE(IPAddress::FromIPLiteral("bad:value", &address));
+  EXPECT_FALSE(IPAddress::FromIPLiteral(std::string(), &address));
+  EXPECT_FALSE(IPAddress::FromIPLiteral("192.168.0.1:30", &address));
+  EXPECT_FALSE(IPAddress::FromIPLiteral("  192.168.0.1  ", &address));
+  EXPECT_FALSE(IPAddress::FromIPLiteral("[::1]", &address));
+}
+
+// Test parsing an IPv4 literal.
+TEST(IPAddressTest, FromIPLiteral_IPv4) {
+  IPAddress address;
+  EXPECT_TRUE(IPAddress::FromIPLiteral("192.168.0.1", &address));
+  EXPECT_EQ("192,168,0,1", DumpIPAddress(address));
+  EXPECT_EQ("192.168.0.1", address.ToString());
+}
+
+// Test parsing an IPv6 literal.
+TEST(IPAddressTest, FromIPLiteral_IPv6) {
+  IPAddress address;
+  EXPECT_TRUE(IPAddress::FromIPLiteral("1:abcd::3:4:ff", &address));
+  EXPECT_EQ("0,1,171,205,0,0,0,0,0,0,0,3,0,4,0,255", DumpIPAddress(address));
+  EXPECT_EQ("1:abcd::3:4:ff", address.ToString());
+}
+
+TEST(IPAddressTest, IsIPv4Mapped) {
+  IPAddress ipv4_address;
+  EXPECT_TRUE(IPAddress::FromIPLiteral("192.168.0.1", &ipv4_address));
+  EXPECT_FALSE(ipv4_address.IsIPv4Mapped());
+
+  IPAddress ipv6_address;
+  EXPECT_TRUE(IPAddress::FromIPLiteral("::1", &ipv4_address));
+  EXPECT_FALSE(ipv6_address.IsIPv4Mapped());
+
+  IPAddress ipv4mapped_address;
+  EXPECT_TRUE(IPAddress::FromIPLiteral("::ffff:0101:1", &ipv4mapped_address));
+  EXPECT_TRUE(ipv4mapped_address.IsIPv4Mapped());
+}
+
+TEST(IPAddressTest, IsEqual) {
+  IPAddress ip_address1;
+  EXPECT_TRUE(IPAddress::FromIPLiteral("127.0.0.1", &ip_address1));
+  IPAddress ip_address2;
+  EXPECT_TRUE(IPAddress::FromIPLiteral("2001:db8:0::42", &ip_address2));
+  IPAddress ip_address3;
+  EXPECT_TRUE(IPAddress::FromIPLiteral("127.0.0.1", &ip_address3));
+
+  EXPECT_FALSE(ip_address1 == ip_address2);
+  EXPECT_TRUE(ip_address1 == ip_address3);
+}
+
+TEST(IPAddressTest, LessThan) {
+  // IPv4 vs IPv6
+  IPAddress ip_address1;
+  EXPECT_TRUE(IPAddress::FromIPLiteral("127.0.0.1", &ip_address1));
+  IPAddress ip_address2;
+  EXPECT_TRUE(IPAddress::FromIPLiteral("2001:db8:0::42", &ip_address2));
+  EXPECT_TRUE(ip_address1 < ip_address2);
+  EXPECT_FALSE(ip_address2 < ip_address1);
+
+  // Compare equivalent addresses.
+  IPAddress ip_address3;
+  EXPECT_TRUE(IPAddress::FromIPLiteral("127.0.0.1", &ip_address3));
+  EXPECT_FALSE(ip_address1 < ip_address3);
+  EXPECT_FALSE(ip_address3 < ip_address1);
+}
+
+}  // anonymous namespace
+
+}  // namespace net
diff --git a/net/base/stale_while_revalidate_experiment_domains.gperf b/net/base/stale_while_revalidate_experiment_domains.gperf
index 24bf21a..06917432 100644
--- a/net/base/stale_while_revalidate_experiment_domains.gperf
+++ b/net/base/stale_while_revalidate_experiment_domains.gperf
@@ -1,117 +1,116 @@
 %{
 
-// List of top 98 domains* which are expected to benefit from the implementation
-// of the stale-while-revalidate Cache-Control directive. The list is derived
-// from public information (the HTTPArchive) and ordered by ranking. This list
+// List of top 100 domains which are expected to benefit from the implementation
+// of the stale-while-revalidate Cache-Control directive. This list
 // is only used to generate histograms to measure the effectiveness of the
 // feature. These domains are given no special treatment.
 //
 // This file is temporary for the duration of the evaluation of the
-// stale-while-revalidate feature.
+// stale-while-revalidate feature. crbug.com/564517
 
 // This file is converted to a DAFSA by make_dafsa.py.
 
-// *Two domains appear in effective_tld_names.dat and so were manually removed.
-
 %}
 
 %%
-blogspot.com, 0
-wordpress.com, 0
-blogspot.in, 0
-tumblr.com, 0
-blogspot.com.br, 0
-myshopify.com, 0
-blogspot.gr, 0
-altervista.org, 0
-weebly.com, 0
-blogspot.com.es, 0
-blogspot.it, 0
-uol.com.br, 0
-blogspot.pt, 0
-blogspot.co.uk, 0
-blogspot.mx, 0
-appspot.com, 0
-blogspot.fr, 0
-blogspot.com.tr, 0
-blog.pl, 0
-squarespace.com, 0
-blogspot.com.ar, 0
-jimdo.com, 0
-blogspot.ca, 0
-mybigcommerce.com, 0
-blogspot.sg, 0
-typepad.com, 0
-blogspot.com.au, 0
-esy.es, 0
-sapo.pt, 0
-over-blog.com, 0
-blogspot.ro, 0
-ucoz.ru, 0
-webnode.com, 0
-livejournal.com, 0
-16mb.com, 0
-blogspot.nl, 0
-narod.ru, 0
-sextgem.com, 0
-us.com, 0
-ecwid.com, 0
-ucoz.com, 0
-tripod.com, 0
-n.nu, 0
-ning.com, 0
-free.fr, 0
-webs.com, 0
-sitew.com, 0
-onclickads.net, 0
-diply.com, 0
-adcash.com, 0
+123rf.com, 0
+academia.edu, 0
+avclub.com, 0
+baixaki.com.br, 0
+bgr.com, 0
+britannica.com, 0
+buenastareas.com, 0
+buscape.com.br, 0
+cbslocal.com, 0
+cbssports.com, 0
+ccm.net, 0
+chegg.com, 0
+clarin.com, 0
+commentcamarche.net, 0
+coursehero.com, 0
+crunchbase.com, 0
+deadline.com, 0
+dicionarioinformal.com.br, 0
+digitaltrends.com, 0
 dropbox.com, 0
-directrev.com, 0
-weather.com, 0
-deviantart.com, 0
-terraclicks.com, 0
-taboola.com, 0
-abs-cbnnews.com, 0
-wordpress.org, 0
-w3schools.com, 0
-mediafire.com, 0
-mystart.com, 0
-doublepimp.com, 0
-ndtv.com, 0
-youm7.com, 0
-addthis.com, 0
-popcash.net, 0
-sourceforge.net, 0
-likes.com, 0
-chinatimes.com, 0
-speedtest.net, 0
-kaskus.co.id, 0
-stumbleupon.com, 0
-reimageplus.com, 0
-conservativetribune.com, 0
-hootsuite.com, 0
-slickdeals.net, 0
-samsung.com, 0
-buzzfil.net, 0
-elmogaz.com, 0
-bhaskar.com, 0
-wow.com, 0
-marca.com, 0
-kompas.com, 0
-xda-developers.com, 0
-naukri.com, 0
-flirchi.com, 0
-bookmyshow.com, 0
-independent.co.uk, 0
-urdupoint.com, 0
-exoclick.com, 0
-slack.com, 0
-moneycontrol.com, 0
-pof.com, 0
-onedio.com, 0
-nasa.gov, 0
+encyclopedia.com, 0
+enotes.com, 0
+eonline.com, 0
+express.co.uk, 0
+extradeportes.net, 0
+firstpost.com, 0
+food.com, 0
+foxnews.com, 0
+giphy.com, 0
+gmailblog.blogspot.com, 0
+goodreads.com, 0
+googleapps.com, 0
+googleblog.blogspot.com, 0
+guiamais.com.br, 0
+gumtree.com, 0
+haberler.com, 0
+heavy.com, 0
+history.com, 0
+hollywoodlife.com, 0
+howtogeek.com, 0
+ibtimes.co.in, 0
+ilpost.it, 0
+iltalehti.fi, 0
+iltasanomat.fi, 0
 instructables.com, 0
-savefrom.net, 0
-issuu.com, 0
+journaldesfemmes.com, 0
+kekanto.com.br, 0
+lavanguardia.com, 0
+legacy.com, 0
+liberoquotidiano.it, 0
+linternaute.com, 0
+livescience.com, 0
+lolking.net, 0
+marmiton.org, 0
+meinestadt.de, 0
+merriam-webster.com, 0
+miniclip.com, 0
+mmajunkie.com, 0
+mobile01.com, 0
+moviepilot.de, 0
+mymovies.it, 0
+naszemiasto.pl, 0
+natemat.pl, 0
+ndtv.com, 0
+nesn.com, 0
+paginegialle.it, 0
+parismatch.com, 0
+popsugar.com, 0
+prezi.com, 0
+programme-tv.net, 0
+purepeople.com, 0
+qz.com, 0
+radaronline.com, 0
+shmoop.com, 0
+slate.fr, 0
+sondakika.com, 0
+songtexte.com, 0
+study.com, 0
+superpages.com, 0
+techtimes.com, 0
+tecmundo.com.br, 0
+telegraaf.nl, 0
+tf1.fr, 0
+tv.com, 0
+tvline.com, 0
+variety.com, 0
+venturebeat.com, 0
+vocabulary.com, 0
+wattpad.com, 0
+weather.com, 0
+weebly.com, 0
+whitepages.com, 0
+wordpress.com, 0
+wordpress.org, 0
+xda-developers.com, 0
+yourdictionary.com, 0
+zadane.pl, 0
+zillow.com, 0
+znanija.com, 0
+zoopla.co.uk, 0
 %%
diff --git a/net/base/stale_while_revalidate_experiment_domains_unittest.cc b/net/base/stale_while_revalidate_experiment_domains_unittest.cc
index 05f0d1af..9b6b844 100644
--- a/net/base/stale_while_revalidate_experiment_domains_unittest.cc
+++ b/net/base/stale_while_revalidate_experiment_domains_unittest.cc
@@ -20,7 +20,7 @@
   bool result;
 } kExpectations[] = {
     {"wordpress.com", true},
-    {"issuu.com", true},
+    {"tf1.fr", true},
     {"wordpress.com.", true},
     {"www.wordpress.com", true},
     {"www.wordpress.com.", true},
diff --git a/net/cert/ct_log_verifier_unittest.cc b/net/cert/ct_log_verifier_unittest.cc
index bc6e61cd..fd15b1e 100644
--- a/net/cert/ct_log_verifier_unittest.cc
+++ b/net/cert/ct_log_verifier_unittest.cc
@@ -20,7 +20,7 @@
 
   void SetUp() override {
     log_ = CTLogVerifier::Create(ct::GetTestPublicKey(), "testlog",
-                                 "https://ct.example.com").Pass();
+                                 "https://ct.example.com");
 
     ASSERT_TRUE(log_);
     ASSERT_EQ(log_->key_id(), ct::GetTestPublicKeyId());
diff --git a/net/cert/ct_objects_extractor_unittest.cc b/net/cert/ct_objects_extractor_unittest.cc
index 864686a..5bb59ba 100644
--- a/net/cert/ct_objects_extractor_unittest.cc
+++ b/net/cert/ct_objects_extractor_unittest.cc
@@ -32,7 +32,7 @@
                                                   der_test_cert.length());
 
     log_ = CTLogVerifier::Create(ct::GetTestPublicKey(), "testlog",
-                                 "https://ct.example.com").Pass();
+                                 "https://ct.example.com");
     ASSERT_TRUE(log_);
   }
 
diff --git a/net/disk_cache/blockfile/backend_impl.cc b/net/disk_cache/blockfile/backend_impl.cc
index 97f3520..f54128f 100644
--- a/net/disk_cache/blockfile/backend_impl.cc
+++ b/net/disk_cache/blockfile/backend_impl.cc
@@ -4,6 +4,8 @@
 
 #include "net/disk_cache/blockfile/backend_impl.h"
 
+#include <limits>
+
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/files/file.h"
@@ -53,7 +55,7 @@
 // Avoid trimming the cache for the first 5 minutes (10 timer ticks).
 const int kTrimDelay = 10;
 
-int DesiredIndexTableLen(int32 storage_size) {
+int DesiredIndexTableLen(int32_t storage_size) {
   if (storage_size <= k64kEntriesStore)
     return kBaseTableLen;
   if (storage_size <= k64kEntriesStore * 2)
@@ -63,7 +65,7 @@
   if (storage_size <= k64kEntriesStore * 8)
     return kBaseTableLen * 8;
 
-  // The biggest storage_size for int32 requires a 4 MB table.
+  // The biggest storage_size for int32_t requires a 4 MB table.
   return kBaseTableLen * 16;
 }
 
@@ -139,7 +141,7 @@
 
 BackendImpl::BackendImpl(
     const base::FilePath& path,
-    uint32 mask,
+    uint32_t mask,
     const scoped_refptr<base::SingleThreadTaskRunner>& cache_thread,
     net::NetLog* net_log)
     : background_queue_(this, cache_thread),
@@ -161,8 +163,7 @@
       user_load_(false),
       net_log_(net_log),
       done_(true, false),
-      ptr_factory_(this) {
-}
+      ptr_factory_(this) {}
 
 BackendImpl::~BackendImpl() {
   if (user_flags_ & kNoRandom) {
@@ -458,7 +459,7 @@
   if (disabled_)
     return;
 
-  uint32 hash = base::Hash(key);
+  uint32_t hash = base::Hash(key);
   bool error;
   EntryImpl* cache_entry = MatchEntry(key, hash, false, Addr(), &error);
   if (cache_entry) {
@@ -474,7 +475,7 @@
     return NULL;
 
   TimeTicks start = TimeTicks::Now();
-  uint32 hash = base::Hash(key);
+  uint32_t hash = base::Hash(key);
   Trace("Open hash 0x%x", hash);
 
   bool error;
@@ -489,9 +490,9 @@
   }
 
   int current_size = data_->header.num_bytes / (1024 * 1024);
-  int64 total_hours = stats_.GetCounter(Stats::TIMER) / 120;
-  int64 no_use_hours = stats_.GetCounter(Stats::LAST_REPORT_TIMER) / 120;
-  int64 use_hours = total_hours - no_use_hours;
+  int64_t total_hours = stats_.GetCounter(Stats::TIMER) / 120;
+  int64_t no_use_hours = stats_.GetCounter(Stats::LAST_REPORT_TIMER) / 120;
+  int64_t use_hours = total_hours - no_use_hours;
 
   if (!cache_entry) {
     CACHE_UMA(AGE_MS, "OpenTime.Miss", 0, start);
@@ -525,7 +526,7 @@
     return NULL;
 
   TimeTicks start = TimeTicks::Now();
-  uint32 hash = base::Hash(key);
+  uint32_t hash = base::Hash(key);
   Trace("Create hash 0x%x", hash);
 
   scoped_refptr<EntryImpl> parent;
@@ -697,8 +698,11 @@
     return true;
 
   // Avoid a DCHECK later on.
-  if (max_bytes >= kint32max - kint32max / 10)
-    max_bytes = kint32max - kint32max / 10 - 1;
+  if (max_bytes >= std::numeric_limits<int32_t>::max() -
+                       std::numeric_limits<int32_t>::max() / 10) {
+    max_bytes = std::numeric_limits<int32_t>::max() -
+                std::numeric_limits<int32_t>::max() / 10 - 1;
+  }
 
   user_flags_ |= kMaxSize;
   max_size_ = max_bytes;
@@ -792,7 +796,7 @@
     return;
   }
 
-  uint32 hash = cache_entry->GetHash();
+  uint32_t hash = cache_entry->GetHash();
   cache_entry->Release();
 
   // Anything on the table means that this entry is there.
@@ -804,7 +808,7 @@
 }
 
 void BackendImpl::InternalDoomEntry(EntryImpl* entry) {
-  uint32 hash = entry->GetHash();
+  uint32_t hash = entry->GetHash();
   std::string key = entry->GetKey();
   Addr entry_addr = entry->entry()->address();
   bool error;
@@ -851,7 +855,7 @@
 
 void BackendImpl::NotLinked(EntryImpl* entry) {
   Addr entry_addr = entry->entry()->address();
-  uint32 i = entry->GetHash() & mask_;
+  uint32_t i = entry->GetHash() & mask_;
   Addr address(data_->table[i]);
   if (!address.is_initialized())
     return;
@@ -906,7 +910,7 @@
   return NULL;
 }
 
-int32 BackendImpl::GetCurrentEntryId() const {
+int32_t BackendImpl::GetCurrentEntryId() const {
   return data_->header.this_id;
 }
 
@@ -914,7 +918,7 @@
   return cache_type() == net::PNACL_CACHE ? max_size_ : max_size_ / 8;
 }
 
-void BackendImpl::ModifyStorageSize(int32 old_size, int32 new_size) {
+void BackendImpl::ModifyStorageSize(int32_t old_size, int32_t new_size) {
   if (disabled_ || old_size == new_size)
     return;
   if (old_size > new_size)
@@ -928,7 +932,7 @@
   stats_.ModifyStorageStats(old_size, new_size);
 }
 
-void BackendImpl::TooMuchStorageRequested(int32 size) {
+void BackendImpl::TooMuchStorageRequested(int32_t size) {
   stats_.ModifyStorageStats(0, size);
 }
 
@@ -977,7 +981,7 @@
     return uma_report_ == 2;
 
   uma_report_++;
-  int64 last_report = stats_.GetCounter(Stats::LAST_REPORT);
+  int64_t last_report = stats_.GetCounter(Stats::LAST_REPORT);
   Time last_time = Time::FromInternalValue(last_report);
   if (!last_report || (Time::Now() - last_time).InDays() >= 7) {
     stats_.SetCounter(Stats::LAST_REPORT, Time::Now().ToInternalValue());
@@ -995,7 +999,7 @@
   Time create_time = Time::FromInternalValue(data_->header.create_time);
   CACHE_UMA(AGE, "FillupAge", 0, create_time);
 
-  int64 use_time = stats_.GetCounter(Stats::TIMER);
+  int64_t use_time = stats_.GetCounter(Stats::TIMER);
   CACHE_UMA(HOURS, "FillupTime", 0, static_cast<int>(use_time / 120));
   CACHE_UMA(PERCENTAGE, "FirstHitRatio", 0, stats_.GetHitRatio());
 
@@ -1059,14 +1063,14 @@
   stats_.OnEvent(an_event);
 }
 
-void BackendImpl::OnRead(int32 bytes) {
+void BackendImpl::OnRead(int32_t bytes) {
   DCHECK_GE(bytes, 0);
   byte_count_ += bytes;
   if (byte_count_ < 0)
-    byte_count_ = kint32max;
+    byte_count_ = std::numeric_limits<int32_t>::max();
 }
 
-void BackendImpl::OnWrite(int32 bytes) {
+void BackendImpl::OnWrite(int32_t bytes) {
   // We use the same implementation as OnRead... just log the number of bytes.
   OnRead(bytes);
 }
@@ -1076,13 +1080,13 @@
     return;
 
   stats_.OnEvent(Stats::TIMER);
-  int64 time = stats_.GetCounter(Stats::TIMER);
-  int64 current = stats_.GetCounter(Stats::OPEN_ENTRIES);
+  int64_t time = stats_.GetCounter(Stats::TIMER);
+  int64_t current = stats_.GetCounter(Stats::OPEN_ENTRIES);
 
   // OPEN_ENTRIES is a sampled average of the number of open entries, avoiding
   // the bias towards 0.
   if (num_refs_ && (current != num_refs_)) {
-    int64 diff = (num_refs_ - current) / 50;
+    int64_t diff = (num_refs_ - current) / 50;
     if (!diff)
       diff = num_refs_ > current ? 1 : -1;
     current = current + diff;
@@ -1137,7 +1141,7 @@
   new_eviction_ = true;
 }
 
-void BackendImpl::SetFlags(uint32 flags) {
+void BackendImpl::SetFlags(uint32_t flags) {
   user_flags_ |= flags;
 }
 
@@ -1205,12 +1209,12 @@
   return cache_type_;
 }
 
-int32 BackendImpl::GetEntryCount() const {
+int32_t BackendImpl::GetEntryCount() const {
   if (!index_.get() || disabled_)
     return 0;
   // num_entries includes entries already evicted.
-  int32 not_deleted = data_->header.num_entries -
-                      data_->header.lru.sizes[Rankings::DELETED];
+  int32_t not_deleted =
+      data_->header.num_entries - data_->header.lru.sizes[Rankings::DELETED];
 
   if (not_deleted < 0) {
     NOTREACHED();
@@ -1402,7 +1406,7 @@
   DCHECK(!table_len || data_->header.magic);
 
   // The user is not setting the size, let's figure it out.
-  int64 available = base::SysInfo::AmountOfFreeDiskSpace(path_);
+  int64_t available = base::SysInfo::AmountOfFreeDiskSpace(path_);
   if (available < 0) {
     max_size_ = kDefaultCacheSize;
     return;
@@ -1481,10 +1485,10 @@
 }
 
 void BackendImpl::RestartCache(bool failure) {
-  int64 errors = stats_.GetCounter(Stats::FATAL_ERROR);
-  int64 full_dooms = stats_.GetCounter(Stats::DOOM_CACHE);
-  int64 partial_dooms = stats_.GetCounter(Stats::DOOM_RECENT);
-  int64 last_report = stats_.GetCounter(Stats::LAST_REPORT);
+  int64_t errors = stats_.GetCounter(Stats::FATAL_ERROR);
+  int64_t full_dooms = stats_.GetCounter(Stats::DOOM_CACHE);
+  int64_t partial_dooms = stats_.GetCounter(Stats::DOOM_RECENT);
+  int64_t last_report = stats_.GetCounter(Stats::LAST_REPORT);
 
   PrepareForRestart();
   if (failure) {
@@ -1603,8 +1607,10 @@
   return 0;
 }
 
-EntryImpl* BackendImpl::MatchEntry(const std::string& key, uint32 hash,
-                                   bool find_parent, Addr entry_addr,
+EntryImpl* BackendImpl::MatchEntry(const std::string& key,
+                                   uint32_t hash,
+                                   bool find_parent,
+                                   Addr entry_addr,
                                    bool* match_error) {
   Addr address(data_->table[hash & mask_]);
   scoped_refptr<EntryImpl> cache_entry, parent_entry;
@@ -1808,12 +1814,12 @@
   stats_.OnEvent(Stats::INVALID_ENTRY);
 }
 
-void BackendImpl::AddStorageSize(int32 bytes) {
+void BackendImpl::AddStorageSize(int32_t bytes) {
   data_->header.num_bytes += bytes;
   DCHECK_GE(data_->header.num_bytes, 0);
 }
 
-void BackendImpl::SubstractStorageSize(int32 bytes) {
+void BackendImpl::SubstractStorageSize(int32_t bytes) {
   data_->header.num_bytes -= bytes;
   DCHECK_GE(data_->header.num_bytes, 0);
 }
@@ -1893,7 +1899,7 @@
   if (age)
     CACHE_UMA(HOURS, "FilesAge", 0, age);
 
-  int64 total_hours = stats_.GetCounter(Stats::TIMER) / 120;
+  int64_t total_hours = stats_.GetCounter(Stats::TIMER) / 120;
   if (!data_->header.create_time || !data_->header.lru.filled) {
     int cause = data_->header.create_time ? 0 : 1;
     if (!data_->header.lru.filled)
@@ -1913,7 +1919,7 @@
   if (base::RandInt(0, 99) < hit_ratio_as_percentage)
     CACHE_UMA(HOURS, "HitRatioByTotalTime", 0, static_cast<int>(total_hours));
 
-  int64 use_hours = stats_.GetCounter(Stats::LAST_REPORT_TIMER) / 120;
+  int64_t use_hours = stats_.GetCounter(Stats::LAST_REPORT_TIMER) / 120;
   stats_.SetCounter(Stats::LAST_REPORT_TIMER, stats_.GetCounter(Stats::TIMER));
 
   // We may see users with no use_hours at this point if this is the first time
@@ -1932,7 +1938,7 @@
     CACHE_UMA(HOURS, "HitRatioByUseTime", 0, static_cast<int>(use_hours));
   CACHE_UMA(PERCENTAGE, "HitRatio", 0, hit_ratio_as_percentage);
 
-  int64 trim_rate = stats_.GetCounter(Stats::TRIM_ENTRY) / use_hours;
+  int64_t trim_rate = stats_.GetCounter(Stats::TRIM_ENTRY) / use_hours;
   CACHE_UMA(COUNTS, "TrimRate", 0, static_cast<int>(trim_rate));
 
   int avg_size = data_->header.num_bytes / GetEntryCount();
@@ -2016,7 +2022,7 @@
 
 #if !defined(NET_BUILD_STRESS_CACHE)
   if (data_->header.num_bytes < 0 ||
-      (max_size_ < kint32max - kDefaultCacheSize &&
+      (max_size_ < std::numeric_limits<int32_t>::max() - kDefaultCacheSize &&
        data_->header.num_bytes > max_size_ + kDefaultCacheSize)) {
     LOG(ERROR) << "Invalid cache (current) size";
     return false;
@@ -2038,7 +2044,7 @@
 int BackendImpl::CheckAllEntries() {
   int num_dirty = 0;
   int num_entries = 0;
-  DCHECK(mask_ < kuint32max);
+  DCHECK(mask_ < std::numeric_limits<uint32_t>::max());
   for (unsigned int i = 0; i <= mask_; i++) {
     Addr address(data_->table[i]);
     if (!address.is_initialized())
@@ -2094,7 +2100,7 @@
 }
 
 int BackendImpl::MaxBuffersSize() {
-  static int64 total_memory = base::SysInfo::AmountOfPhysicalMemory();
+  static int64_t total_memory = base::SysInfo::AmountOfPhysicalMemory();
   static bool done = false;
 
   if (!done) {
diff --git a/net/disk_cache/blockfile/backend_impl.h b/net/disk_cache/blockfile/backend_impl.h
index f888468..c5177a2 100644
--- a/net/disk_cache/blockfile/backend_impl.h
+++ b/net/disk_cache/blockfile/backend_impl.h
@@ -7,6 +7,8 @@
 #ifndef NET_DISK_CACHE_BLOCKFILE_BACKEND_IMPL_H_
 #define NET_DISK_CACHE_BLOCKFILE_BACKEND_IMPL_H_
 
+#include <stdint.h>
+
 #include "base/containers/hash_tables.h"
 #include "base/files/file_path.h"
 #include "base/memory/ref_counted.h"
@@ -54,7 +56,7 @@
               net::NetLog* net_log);
   // mask can be used to limit the usable size of the hash table, for testing.
   BackendImpl(const base::FilePath& path,
-              uint32 mask,
+              uint32_t mask,
               const scoped_refptr<base::SingleThreadTaskRunner>& cache_thread,
               net::NetLog* net_log);
   ~BackendImpl() override;
@@ -149,16 +151,16 @@
   EntryImpl* GetOpenEntry(CacheRankingsBlock* rankings) const;
 
   // Returns the id being used on this run of the cache.
-  int32 GetCurrentEntryId() const;
+  int32_t GetCurrentEntryId() const;
 
   // Returns the maximum size for a file to reside on the cache.
   int MaxFileSize() const;
 
   // A user data block is being created, extended or truncated.
-  void ModifyStorageSize(int32 old_size, int32 new_size);
+  void ModifyStorageSize(int32_t old_size, int32_t new_size);
 
   // Logs requests that are denied due to being too big.
-  void TooMuchStorageRequested(int32 size);
+  void TooMuchStorageRequested(int32_t size);
 
   // Returns true if a temporary buffer is allowed to be extended.
   bool IsAllocAllowed(int current_size, int new_size);
@@ -228,7 +230,7 @@
   void SetNewEviction();
 
   // Sets an explicit set of BackendFlags.
-  void SetFlags(uint32 flags);
+  void SetFlags(uint32_t flags);
 
   // Clears the counter of references to test handling of corruptions.
   void ClearRefCountForTest();
@@ -261,7 +263,7 @@
 
   // Backend implementation.
   net::CacheType GetCacheType() const override;
-  int32 GetEntryCount() const override;
+  int32_t GetEntryCount() const override;
   int OpenEntry(const std::string& key,
                 Entry** entry,
                 const CompletionCallback& callback) override;
@@ -316,8 +318,11 @@
   // if it doesn't match the entry on the index, we know that it was replaced
   // with a new entry; in this case |*match_error| will be set to true and the
   // return value will be NULL.
-  EntryImpl* MatchEntry(const std::string& key, uint32 hash, bool find_parent,
-                        Addr entry_addr, bool* match_error);
+  EntryImpl* MatchEntry(const std::string& key,
+                        uint32_t hash,
+                        bool find_parent,
+                        Addr entry_addr,
+                        bool* match_error);
 
   // Opens the next or previous entry on a single list. If successful,
   // |from_entry| will be updated to point to the new entry, otherwise it will
@@ -335,8 +340,8 @@
   void DestroyInvalidEntry(EntryImpl* entry);
 
   // Handles the used storage count.
-  void AddStorageSize(int32 bytes);
-  void SubstractStorageSize(int32 bytes);
+  void AddStorageSize(int32_t bytes);
+  void SubstractStorageSize(int32_t bytes);
 
   // Update the number of referenced cache entries.
   void IncreaseNumRefs();
@@ -371,8 +376,8 @@
   Index* data_;  // Pointer to the index data.
   BlockFiles block_files_;  // Set of files used to store all data.
   Rankings rankings_;  // Rankings to be able to trim the cache.
-  uint32 mask_;  // Binary mask to map a hash to the hash table.
-  int32 max_size_;  // Maximum data size for this instance.
+  uint32_t mask_;            // Binary mask to map a hash to the hash table.
+  int32_t max_size_;         // Maximum data size for this instance.
   Eviction eviction_;  // Handler of the eviction algorithm.
   EntriesMap open_entries_;  // Map of open entries.
   int num_refs_;  // Number of referenced cache entries.
@@ -384,7 +389,7 @@
   int up_ticks_;  // The number of timer ticks received (OnStatsTimer).
   net::CacheType cache_type_;
   int uma_report_;  // Controls transmission of UMA data.
-  uint32 user_flags_;  // Flags set by the user.
+  uint32_t user_flags_;  // Flags set by the user.
   bool init_;  // controls the initialization of the system.
   bool restarted_;
   bool unit_test_;
diff --git a/net/disk_cache/blockfile/backend_impl_v3.cc b/net/disk_cache/blockfile/backend_impl_v3.cc
index fe944e8..ae90bd96 100644
--- a/net/disk_cache/blockfile/backend_impl_v3.cc
+++ b/net/disk_cache/blockfile/backend_impl_v3.cc
@@ -4,6 +4,8 @@
 
 #include "net/disk_cache/blockfile/backend_impl_v3.h"
 
+#include <limits>
+
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/files/file_path.h"
@@ -100,8 +102,11 @@
     return true;
 
   // Avoid a DCHECK later on.
-  if (max_bytes >= kint32max - kint32max / 10)
-    max_bytes = kint32max - kint32max / 10 - 1;
+  if (max_bytes >= std::numeric_limits<int32_t>::max() -
+                       std::numeric_limits<int32_t>::max() / 10) {
+    max_bytes = std::numeric_limits<int32_t>::max() -
+                std::numeric_limits<int32_t>::max() / 10 - 1;
+  }
 
   user_flags_ |= MAX_SIZE;
   max_size_ = max_bytes;
@@ -126,7 +131,7 @@
 }
 
 void BackendImplV3::InternalDoomEntry(EntryImplV3* entry) {
-  uint32 hash = entry->GetHash();
+  uint32_t hash = entry->GetHash();
   std::string key = entry->GetKey();
   Addr entry_addr = entry->entry()->address();
   bool error;
@@ -184,7 +189,7 @@
   return max_size_ / 8;
 }
 
-void BackendImplV3::ModifyStorageSize(int32 old_size, int32 new_size) {
+void BackendImplV3::ModifyStorageSize(int32_t old_size, int32_t new_size) {
   if (disabled_ || old_size == new_size)
     return;
   if (old_size > new_size)
@@ -196,7 +201,7 @@
   stats_.ModifyStorageStats(old_size, new_size);
 }
 
-void BackendImplV3::TooMuchStorageRequested(int32 size) {
+void BackendImplV3::TooMuchStorageRequested(int32_t size) {
   stats_.ModifyStorageStats(0, size);
 }
 
@@ -247,7 +252,7 @@
     return uma_report_ == 2;
 
   uma_report_++;
-  int64 last_report = stats_.GetCounter(Stats::LAST_REPORT);
+  int64_t last_report = stats_.GetCounter(Stats::LAST_REPORT);
   Time last_time = Time::FromInternalValue(last_report);
   if (!last_report || (Time::Now() - last_time).InDays() >= 7) {
     stats_.SetCounter(Stats::LAST_REPORT, Time::Now().ToInternalValue());
@@ -267,7 +272,7 @@
   Time create_time = Time::FromInternalValue(header->create_time);
   CACHE_UMA(AGE, "FillupAge", create_time);
 
-  int64 use_time = stats_.GetCounter(Stats::TIMER);
+  int64_t use_time = stats_.GetCounter(Stats::TIMER);
   CACHE_UMA(HOURS, "FillupTime", static_cast<int>(use_time / 120));
   CACHE_UMA(PERCENTAGE, "FirstHitRatio", stats_.GetHitRatio());
 
@@ -302,27 +307,27 @@
   stats_.OnEvent(an_event);
 }
 
-void BackendImplV3::OnRead(int32 bytes) {
+void BackendImplV3::OnRead(int32_t bytes) {
   DCHECK_GE(bytes, 0);
   byte_count_ += bytes;
   if (byte_count_ < 0)
-    byte_count_ = kint32max;
+    byte_count_ = std::numeric_limits<int32_t>::max();
 }
 
-void BackendImplV3::OnWrite(int32 bytes) {
+void BackendImplV3::OnWrite(int32_t bytes) {
   // We use the same implementation as OnRead... just log the number of bytes.
   OnRead(bytes);
 }
 
 void BackendImplV3::OnTimerTick() {
   stats_.OnEvent(Stats::TIMER);
-  int64 time = stats_.GetCounter(Stats::TIMER);
-  int64 current = stats_.GetCounter(Stats::OPEN_ENTRIES);
+  int64_t time = stats_.GetCounter(Stats::TIMER);
+  int64_t current = stats_.GetCounter(Stats::OPEN_ENTRIES);
 
   // OPEN_ENTRIES is a sampled average of the number of open entries, avoiding
   // the bias towards 0.
   if (num_refs_ && (current != num_refs_)) {
-    int64 diff = (num_refs_ - current) / 50;
+    int64_t diff = (num_refs_ - current) / 50;
     if (!diff)
       diff = num_refs_ > current ? 1 : -1;
     current = current + diff;
@@ -368,7 +373,7 @@
   lru_eviction_ = false;
 }
 
-void BackendImplV3::SetFlags(uint32 flags) {
+void BackendImplV3::SetFlags(uint32_t flags) {
   user_flags_ |= flags;
 }
 
@@ -417,7 +422,7 @@
   return cache_type_;
 }
 
-int32 BackendImplV3::GetEntryCount() const {
+int32_t BackendImplV3::GetEntryCount() const {
   if (disabled_)
     return 0;
   DCHECK(init_);
@@ -430,7 +435,7 @@
     return NULL;
 
   TimeTicks start = TimeTicks::Now();
-  uint32 hash = base::Hash(key);
+  uint32_t hash = base::Hash(key);
   Trace("Open hash 0x%x", hash);
 
   bool error;
@@ -442,9 +447,9 @@
   }
 
   int current_size = data_->header.num_bytes / (1024 * 1024);
-  int64 total_hours = stats_.GetCounter(Stats::TIMER) / 120;
-  int64 no_use_hours = stats_.GetCounter(Stats::LAST_REPORT_TIMER) / 120;
-  int64 use_hours = total_hours - no_use_hours;
+  int64_t total_hours = stats_.GetCounter(Stats::TIMER) / 120;
+  int64_t no_use_hours = stats_.GetCounter(Stats::LAST_REPORT_TIMER) / 120;
+  int64_t use_hours = total_hours - no_use_hours;
 
   if (!cache_entry) {
     CACHE_UMA(AGE_MS, "OpenTime.Miss", 0, start);
@@ -717,7 +722,7 @@
   if (disabled_)
     return;
 
-  uint32 hash = base::Hash(key);
+  uint32_t hash = base::Hash(key);
   bool error;
   EntryImpl* cache_entry = MatchEntry(key, hash, false, Addr(), &error);
   if (cache_entry) {
@@ -740,7 +745,7 @@
   DCHECK(!table_len || data_->header.magic);
 
   // The user is not setting the size, let's figure it out.
-  int64 available = base::SysInfo::AmountOfFreeDiskSpace(path_);
+  int64_t available = base::SysInfo::AmountOfFreeDiskSpace(path_);
   if (available < 0) {
     max_size_ = kDefaultCacheSize;
     return;
@@ -822,10 +827,10 @@
 }
 
 void BackendImplV3::RestartCache(bool failure) {
-  int64 errors = stats_.GetCounter(Stats::FATAL_ERROR);
-  int64 full_dooms = stats_.GetCounter(Stats::DOOM_CACHE);
-  int64 partial_dooms = stats_.GetCounter(Stats::DOOM_RECENT);
-  int64 last_report = stats_.GetCounter(Stats::LAST_REPORT);
+  int64_t errors = stats_.GetCounter(Stats::FATAL_ERROR);
+  int64_t full_dooms = stats_.GetCounter(Stats::DOOM_CACHE);
+  int64_t partial_dooms = stats_.GetCounter(Stats::DOOM_RECENT);
+  int64_t last_report = stats_.GetCounter(Stats::LAST_REPORT);
 
   PrepareForRestart();
   if (failure) {
@@ -965,12 +970,12 @@
   return 0;
 }
 
-void BackendImplV3::AddStorageSize(int32 bytes) {
+void BackendImplV3::AddStorageSize(int32_t bytes) {
   data_->header.num_bytes += bytes;
   DCHECK_GE(data_->header.num_bytes, 0);
 }
 
-void BackendImplV3::SubstractStorageSize(int32 bytes) {
+void BackendImplV3::SubstractStorageSize(int32_t bytes) {
   data_->header.num_bytes -= bytes;
   DCHECK_GE(data_->header.num_bytes, 0);
 }
@@ -1262,7 +1267,7 @@
   stats_.SetCounter(Stats::DOOM_CACHE, 0);
   stats_.SetCounter(Stats::DOOM_RECENT, 0);
 
-  int64 total_hours = stats_.GetCounter(Stats::TIMER) / 120;
+  int64_t total_hours = stats_.GetCounter(Stats::TIMER) / 120;
   if (!(header->flags & CACHE_EVICTED)) {
     CACHE_UMA(HOURS, "TotalTimeNotFull", static_cast<int>(total_hours));
     return;
@@ -1273,7 +1278,7 @@
 
   CACHE_UMA(HOURS, "TotalTime", static_cast<int>(total_hours));
 
-  int64 use_hours = stats_.GetCounter(Stats::LAST_REPORT_TIMER) / 120;
+  int64_t use_hours = stats_.GetCounter(Stats::LAST_REPORT_TIMER) / 120;
   stats_.SetCounter(Stats::LAST_REPORT_TIMER, stats_.GetCounter(Stats::TIMER));
 
   // We may see users with no use_hours at this point if this is the first time
@@ -1286,7 +1291,7 @@
 
   CACHE_UMA(HOURS, "UseTime", static_cast<int>(use_hours));
 
-  int64 trim_rate = stats_.GetCounter(Stats::TRIM_ENTRY) / use_hours;
+  int64_t trim_rate = stats_.GetCounter(Stats::TRIM_ENTRY) / use_hours;
   CACHE_UMA(COUNTS, "TrimRate", static_cast<int>(trim_rate));
 
   int avg_size = header->num_bytes / GetEntryCount();
@@ -1368,7 +1373,7 @@
 
 #if !defined(NET_BUILD_STRESS_CACHE)
   if (data_->header.num_bytes < 0 ||
-      (max_size_ < kint32max - kDefaultCacheSize &&
+      (max_size_ < std::numeric_limits<int32_t>::max() - kDefaultCacheSize &&
        data_->header.num_bytes > max_size_ + kDefaultCacheSize)) {
     LOG(ERROR) << "Invalid cache (current) size";
     return false;
@@ -1391,7 +1396,7 @@
 int BackendImplV3::CheckAllEntries() {
   int num_dirty = 0;
   int num_entries = 0;
-  DCHECK(mask_ < kuint32max);
+  DCHECK(mask_ < std::numeric_limits<uint32_t>::max());
   for (unsigned int i = 0; i <= mask_; i++) {
     Addr address(data_->table[i]);
     if (!address.is_initialized())
@@ -1447,7 +1452,7 @@
 }
 
 int BackendImplV3::MaxBuffersSize() {
-  static int64 total_memory = base::SysInfo::AmountOfPhysicalMemory();
+  static int64_t total_memory = base::SysInfo::AmountOfPhysicalMemory();
   static bool done = false;
 
   if (!done) {
@@ -1474,7 +1479,7 @@
   return cache_type_;
 }
 
-int32 BackendImplV3::GetEntryCount() const {
+int32_t BackendImplV3::GetEntryCount() const {
   return 0;
 }
 
diff --git a/net/disk_cache/blockfile/backend_impl_v3.h b/net/disk_cache/blockfile/backend_impl_v3.h
index 7cc4648..d935a9db 100644
--- a/net/disk_cache/blockfile/backend_impl_v3.h
+++ b/net/disk_cache/blockfile/backend_impl_v3.h
@@ -7,6 +7,8 @@
 #ifndef NET_DISK_CACHE_BLOCKFILE_BACKEND_IMPL_V3_H_
 #define NET_DISK_CACHE_BLOCKFILE_BACKEND_IMPL_V3_H_
 
+#include <stdint.h>
+
 #include "base/containers/hash_tables.h"
 #include "base/files/file_path.h"
 #include "base/memory/ref_counted.h"
@@ -86,16 +88,16 @@
   EntryImplV3* GetOpenEntry(Addr address) const;
 
   // Returns the id being used on this run of the cache.
-  int32 GetCurrentEntryId() const;
+  int32_t GetCurrentEntryId() const;
 
   // Returns the maximum size for a file to reside on the cache.
   int MaxFileSize() const;
 
   // A user data block is being created, extended or truncated.
-  void ModifyStorageSize(int32 old_size, int32 new_size);
+  void ModifyStorageSize(int32_t old_size, int32_t new_size);
 
   // Logs requests that are denied due to being too big.
-  void TooMuchStorageRequested(int32 size);
+  void TooMuchStorageRequested(int32_t size);
 
   // Returns true if a temporary buffer is allowed to be extended.
   bool IsAllocAllowed(int current_size, int new_size);
@@ -154,7 +156,7 @@
   void SetNewEviction();
 
   // Sets an explicit set of BackendFlags.
-  void SetFlags(uint32 flags);
+  void SetFlags(uint32_t flags);
 
   // Sends a dummy operation through the operation queue, for unit tests.
   int FlushQueueForTest(const CompletionCallback& callback);
@@ -173,7 +175,7 @@
 
   // Backend implementation.
   net::CacheType GetCacheType() const override;
-  int32 GetEntryCount() const override;
+  int32_t GetEntryCount() const override;
   int OpenEntry(const std::string& key,
                 Entry** entry,
                 const CompletionCallback& callback) override;
@@ -216,8 +218,8 @@
   int NewEntry(Addr address, EntryImplV3** entry);
 
   // Handles the used storage count.
-  void AddStorageSize(int32 bytes);
-  void SubstractStorageSize(int32 bytes);
+  void AddStorageSize(int32_t bytes);
+  void SubstractStorageSize(int32_t bytes);
 
   // Update the number of referenced cache entries.
   void IncreaseNumRefs();
@@ -249,7 +251,7 @@
   IndexTable index_;
   base::FilePath path_;  // Path to the folder used as backing storage.
   BlockBitmaps block_files_;
-  int32 max_size_;  // Maximum data size for this instance.
+  int32_t max_size_;     // Maximum data size for this instance.
   EvictionV3 eviction_;  // Handler of the eviction algorithm.
   EntriesMap open_entries_;
   int num_refs_;  // Number of referenced cache entries.
@@ -260,7 +262,7 @@
   int up_ticks_;  // The number of timer ticks received (OnTimerTick).
   net::CacheType cache_type_;
   int uma_report_;  // Controls transmission of UMA data.
-  uint32 user_flags_;  // Flags set by the user.
+  uint32_t user_flags_;  // Flags set by the user.
   bool init_;  // controls the initialization of the system.
   bool restarted_;
   bool read_only_;  // Prevents updates of the rankings data (used by tools).
diff --git a/net/disk_cache/blockfile/file_ios.cc b/net/disk_cache/blockfile/file_ios.cc
index 3ffb5a5..b00c246 100644
--- a/net/disk_cache/blockfile/file_ios.cc
+++ b/net/disk_cache/blockfile/file_ios.cc
@@ -4,6 +4,10 @@
 
 #include "net/disk_cache/blockfile/file.h"
 
+#include <stdint.h>
+
+#include <limits>
+
 #include "base/bind.h"
 #include "base/location.h"
 #include "base/logging.h"
@@ -188,8 +192,8 @@
 
 bool File::Read(void* buffer, size_t buffer_len, size_t offset) {
   DCHECK(base_file_.IsValid());
-  if (buffer_len > static_cast<size_t>(kint32max) ||
-      offset > static_cast<size_t>(kint32max)) {
+  if (buffer_len > static_cast<size_t>(std::numeric_limits<int32_t>::max()) ||
+      offset > static_cast<size_t>(std::numeric_limits<int32_t>::max())) {
     return false;
   }
 
@@ -199,8 +203,8 @@
 
 bool File::Write(const void* buffer, size_t buffer_len, size_t offset) {
   DCHECK(base_file_.IsValid());
-  if (buffer_len > static_cast<size_t>(kint32max) ||
-      offset > static_cast<size_t>(kint32max)) {
+  if (buffer_len > static_cast<size_t>(std::numeric_limits<int32_t>::max()) ||
+      offset > static_cast<size_t>(std::numeric_limits<int32_t>::max())) {
     return false;
   }
 
@@ -244,7 +248,7 @@
 
 bool File::SetLength(size_t length) {
   DCHECK(base_file_.IsValid());
-  if (length > kuint32max)
+  if (length > std::numeric_limits<uint32_t>::max())
     return false;
 
   return base_file_.SetLength(length);
@@ -252,10 +256,10 @@
 
 size_t File::GetLength() {
   DCHECK(base_file_.IsValid());
-  int64 len = base_file_.GetLength();
+  int64_t len = base_file_.GetLength();
 
-  if (len > static_cast<int64>(kuint32max))
-    return kuint32max;
+  if (len > static_cast<int64_t>(std::numeric_limits<uint32_t>::max()))
+    return std::numeric_limits<uint32_t>::max();
 
   return static_cast<size_t>(len);
 }
diff --git a/net/disk_cache/blockfile/file_posix.cc b/net/disk_cache/blockfile/file_posix.cc
index 828673f9..26067fb 100644
--- a/net/disk_cache/blockfile/file_posix.cc
+++ b/net/disk_cache/blockfile/file_posix.cc
@@ -4,6 +4,10 @@
 
 #include "net/disk_cache/blockfile/file.h"
 
+#include <stdint.h>
+
+#include <limits>
+
 #include "base/bind.h"
 #include "base/lazy_instance.h"
 #include "base/location.h"
@@ -56,8 +60,8 @@
 
 bool File::Read(void* buffer, size_t buffer_len, size_t offset) {
   DCHECK(base_file_.IsValid());
-  if (buffer_len > static_cast<size_t>(kint32max) ||
-      offset > static_cast<size_t>(kint32max)) {
+  if (buffer_len > static_cast<size_t>(std::numeric_limits<int32_t>::max()) ||
+      offset > static_cast<size_t>(std::numeric_limits<int32_t>::max())) {
     return false;
   }
 
@@ -67,8 +71,8 @@
 
 bool File::Write(const void* buffer, size_t buffer_len, size_t offset) {
   DCHECK(base_file_.IsValid());
-  if (buffer_len > static_cast<size_t>(kint32max) ||
-      offset > static_cast<size_t>(kint32max)) {
+  if (buffer_len > static_cast<size_t>(std::numeric_limits<int32_t>::max()) ||
+      offset > static_cast<size_t>(std::numeric_limits<int32_t>::max())) {
     return false;
   }
 
@@ -86,8 +90,8 @@
     return Read(buffer, buffer_len, offset);
   }
 
-  if (buffer_len > static_cast<size_t>(kint32max) ||
-      offset > static_cast<size_t>(kint32max)) {
+  if (buffer_len > static_cast<size_t>(std::numeric_limits<int32_t>::max()) ||
+      offset > static_cast<size_t>(std::numeric_limits<int32_t>::max())) {
     return false;
   }
 
@@ -109,8 +113,8 @@
     return Write(buffer, buffer_len, offset);
   }
 
-  if (buffer_len > static_cast<size_t>(kint32max) ||
-      offset > static_cast<size_t>(kint32max)) {
+  if (buffer_len > static_cast<size_t>(std::numeric_limits<int32_t>::max()) ||
+      offset > static_cast<size_t>(std::numeric_limits<int32_t>::max())) {
     return false;
   }
 
@@ -125,7 +129,7 @@
 
 bool File::SetLength(size_t length) {
   DCHECK(base_file_.IsValid());
-  if (length > kuint32max)
+  if (length > std::numeric_limits<uint32_t>::max())
     return false;
 
   return base_file_.SetLength(length);
@@ -133,10 +137,10 @@
 
 size_t File::GetLength() {
   DCHECK(base_file_.IsValid());
-  int64 len = base_file_.GetLength();
+  int64_t len = base_file_.GetLength();
 
-  if (len > static_cast<int64>(kuint32max))
-    return kuint32max;
+  if (len > static_cast<int64_t>(std::numeric_limits<uint32_t>::max()))
+    return std::numeric_limits<uint32_t>::max();
 
   return static_cast<size_t>(len);
 }
diff --git a/net/dns/dns_response.cc b/net/dns/dns_response.cc
index 663ae0e..c11b8a9c 100644
--- a/net/dns/dns_response.cc
+++ b/net/dns/dns_response.cc
@@ -4,6 +4,8 @@
 
 #include "net/dns/dns_response.h"
 
+#include <limits>
+
 #include "base/big_endian.h"
 #include "base/strings/string_util.h"
 #include "base/sys_byteorder.h"
@@ -61,19 +63,19 @@
     // either a direct length or a pointer to the remainder of the name.
     switch (*p & dns_protocol::kLabelMask) {
       case dns_protocol::kLabelPointer: {
-        if (p + sizeof(uint16) > end)
+        if (p + sizeof(uint16_t) > end)
           return 0;
         if (consumed == 0) {
-          consumed = p - pos + sizeof(uint16);
+          consumed = p - pos + sizeof(uint16_t);
           if (!out)
             return consumed;  // If name is not stored, that's all we need.
         }
-        seen += sizeof(uint16);
+        seen += sizeof(uint16_t);
         // If seen the whole packet, then we must be in a loop.
         if (seen > length_)
           return 0;
-        uint16 offset;
-        base::ReadBigEndian<uint16>(p, &offset);
+        uint16_t offset;
+        base::ReadBigEndian<uint16_t>(p, &offset);
         offset &= dns_protocol::kOffsetMask;
         p = packet_ + offset;
         if (p >= end)
@@ -81,7 +83,7 @@
         break;
       }
       case dns_protocol::kLabelDirect: {
-        uint8 label_len = *p;
+        uint8_t label_len = *p;
         ++p;
         // Note: root domain (".") is NOT included.
         if (label_len == 0) {
@@ -115,7 +117,7 @@
     return false;
   base::BigEndianReader reader(cur_ + consumed,
                                packet_ + length_ - (cur_ + consumed));
-  uint16 rdlen;
+  uint16_t rdlen;
   if (reader.ReadU16(&out->type) &&
       reader.ReadU16(&out->klass) &&
       reader.ReadU32(&out->ttl) &&
@@ -132,7 +134,7 @@
   if (!consumed)
     return false;
 
-  const char* next = cur_ + consumed + 2 * sizeof(uint16);  // QTYPE + QCLASS
+  const char* next = cur_ + consumed + 2 * sizeof(uint16_t);  // QTYPE + QCLASS
   if (next > packet_ + length_)
     return false;
 
@@ -216,12 +218,12 @@
   return parser_.IsValid();
 }
 
-uint16 DnsResponse::flags() const {
+uint16_t DnsResponse::flags() const {
   DCHECK(parser_.IsValid());
   return base::NetToHost16(header()->flags) & ~(dns_protocol::kRcodeMask);
 }
 
-uint8 DnsResponse::rcode() const {
+uint8_t DnsResponse::rcode() const {
   DCHECK(parser_.IsValid());
   return base::NetToHost16(header()->flags) & dns_protocol::kRcodeMask;
 }
@@ -240,18 +242,19 @@
   DCHECK(parser_.IsValid());
   // The response is HEADER QNAME QTYPE QCLASS ANSWER.
   // |parser_| is positioned at the beginning of ANSWER, so the end of QNAME is
-  // two uint16s before it.
+  // two uint16_ts before it.
   const size_t hdr_size = sizeof(dns_protocol::Header);
-  const size_t qname_size = parser_.GetOffset() - 2 * sizeof(uint16) - hdr_size;
+  const size_t qname_size =
+      parser_.GetOffset() - 2 * sizeof(uint16_t) - hdr_size;
   return base::StringPiece(io_buffer_->data() + hdr_size, qname_size);
 }
 
-uint16 DnsResponse::qtype() const {
+uint16_t DnsResponse::qtype() const {
   DCHECK(parser_.IsValid());
   // QTYPE starts where QNAME ends.
-  const size_t type_offset = parser_.GetOffset() - 2 * sizeof(uint16);
-  uint16 type;
-  base::ReadBigEndian<uint16>(io_buffer_->data() + type_offset, &type);
+  const size_t type_offset = parser_.GetOffset() - 2 * sizeof(uint16_t);
+  uint16_t type;
+  base::ReadBigEndian<uint16_t>(io_buffer_->data() + type_offset, &type);
   return type;
 }
 
@@ -282,14 +285,14 @@
   // Expected owner of record. No trailing dot.
   std::string expected_name = GetDottedName();
 
-  uint16 expected_type = qtype();
+  uint16_t expected_type = qtype();
   DCHECK(expected_type == dns_protocol::kTypeA ||
          expected_type == dns_protocol::kTypeAAAA);
 
   size_t expected_size = (expected_type == dns_protocol::kTypeAAAA)
       ? kIPv6AddressSize : kIPv4AddressSize;
 
-  uint32 ttl_sec = kuint32max;
+  uint32_t ttl_sec = std::numeric_limits<uint32_t>::max();
   IPAddressList ip_addresses;
   DnsRecordParser parser = Parser();
   DnsResourceRecord record;
diff --git a/net/dns/dns_response.h b/net/dns/dns_response.h
index 6e67b5dea..24071ca 100644
--- a/net/dns/dns_response.h
+++ b/net/dns/dns_response.h
@@ -5,9 +5,11 @@
 #ifndef NET_DNS_DNS_RESPONSE_H_
 #define NET_DNS_DNS_RESPONSE_H_
 
+#include <stdint.h>
+
 #include <string>
 
-#include "base/basictypes.h"
+#include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/strings/string_piece.h"
 #include "base/time/time.h"
@@ -29,9 +31,9 @@
   ~DnsResourceRecord();
 
   std::string name;  // in dotted form
-  uint16 type;
-  uint16 klass;
-  uint32 ttl;
+  uint16_t type;
+  uint16_t klass;
+  uint32_t ttl;
   base::StringPiece rdata;  // points to the original response buffer
 };
 
@@ -127,15 +129,15 @@
   // All of the methods below are valid only if the response is valid.
 
   // Accessors for the header.
-  uint16 flags() const;  // excluding rcode
-  uint8 rcode() const;
+  uint16_t flags() const;  // excluding rcode
+  uint8_t rcode() const;
 
   unsigned answer_count() const;
   unsigned additional_answer_count() const;
 
   // Accessors to the question. The qname is unparsed.
   base::StringPiece qname() const;
-  uint16 qtype() const;
+  uint16_t qtype() const;
 
   // Returns qname in dotted format.
   std::string GetDottedName() const;
diff --git a/net/http/http_network_transaction_unittest.cc b/net/http/http_network_transaction_unittest.cc
index 8ff5a2fa..26011a8 100644
--- a/net/http/http_network_transaction_unittest.cc
+++ b/net/http/http_network_transaction_unittest.cc
@@ -5882,12 +5882,8 @@
   };
 
   MockRead data_reads[] = {
-    MockRead("HTTP/1.1 200 OK\r\n"),
-    MockRead("Content-Length: 11\r\n\r\n"),
-    MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ),
-    MockRead("hello world"),
-    MockRead(ASYNC, 0, 0)   // EOF
-  };
+      MockRead("HTTP/1.1 200 OK\r\n"), MockRead("Content-Length: 11\r\n\r\n"),
+      MockRead("hello world"), MockRead(ASYNC, ERR_CONNECTION_CLOSED)};
 
   SSLSocketDataProvider ssl(ASYNC, OK);
   SSLSocketDataProvider ssl2(ASYNC, OK);
diff --git a/net/http/http_response_headers_unittest.cc b/net/http/http_response_headers_unittest.cc
index df1b76d..1bc99bb 100644
--- a/net/http/http_response_headers_unittest.cc
+++ b/net/http/http_response_headers_unittest.cc
@@ -23,8 +23,9 @@
 struct TestData {
   const char* raw_headers;
   const char* expected_headers;
-  int expected_response_code;
   HttpVersion expected_version;
+  int expected_response_code;
+  const char* expected_status_text;
 };
 
 class HttpResponseHeadersTest : public testing::Test {
@@ -110,14 +111,13 @@
 
   EXPECT_EQ(expected_headers, headers);
 
-  EXPECT_EQ(test.expected_response_code, parsed->response_code());
-
   EXPECT_TRUE(test.expected_version == parsed->GetHttpVersion());
+  EXPECT_EQ(test.expected_response_code, parsed->response_code());
+  EXPECT_EQ(test.expected_status_text, parsed->GetStatusText());
 }
 
 TestData response_headers_tests[] = {
-    {// Normalise whitespace.
-
+    {// Normalize whitespace.
      "HTTP/1.1    202   Accepted  \n"
      "Content-TYPE  : text/html; charset=utf-8  \n"
      "Set-Cookie: a \n"
@@ -127,10 +127,8 @@
      "Content-TYPE: text/html; charset=utf-8\n"
      "Set-Cookie: a, b\n",
 
-     202,
-     HttpVersion(1, 1)},
+     HttpVersion(1, 1), 202, "Accepted"},
     {// Normalize leading whitespace.
-
      "HTTP/1.1    202   Accepted  \n"
      // Starts with space -- will be skipped as invalid.
      "  Content-TYPE  : text/html; charset=utf-8  \n"
@@ -140,10 +138,14 @@
      "HTTP/1.1 202 Accepted\n"
      "Set-Cookie: a, b\n",
 
-     202,
-     HttpVersion(1, 1)},
-    {// Normalize blank headers.
+     HttpVersion(1, 1), 202, "Accepted"},
+    {// Keep whitespace within status text.
+     "HTTP/1.0 404 Not   found  \n",
 
+     "HTTP/1.0 404 Not   found\n",
+
+     HttpVersion(1, 0), 404, "Not   found"},
+    {// Normalize blank headers.
      "HTTP/1.1 200 OK\n"
      "Header1 :          \n"
      "Header2: \n"
@@ -157,66 +159,58 @@
      "Header3: \n"
      "Header5: \n",
 
-     200,
-     HttpVersion(1, 1)},
+     HttpVersion(1, 1), 200, "OK"},
     {// Don't believe the http/0.9 version if there are headers!
-
      "hTtP/0.9 201\n"
      "Content-TYPE: text/html; charset=utf-8\n",
 
      "HTTP/1.0 201\n"
      "Content-TYPE: text/html; charset=utf-8\n",
 
-     201,
-     HttpVersion(1, 0)},
+     HttpVersion(1, 0), 201, ""},
     {// Accept the HTTP/0.9 version number if there are no headers.
      // This is how HTTP/0.9 responses get constructed from
      // HttpNetworkTransaction.
-
      "hTtP/0.9 200 OK\n",
 
      "HTTP/0.9 200 OK\n",
 
-     200,
-     HttpVersion(0, 9)},
+     HttpVersion(0, 9), 200, "OK"},
     {// Do not add missing status text.
-
      "HTTP/1.1 201\n"
      "Content-TYPE: text/html; charset=utf-8\n",
 
      "HTTP/1.1 201\n"
      "Content-TYPE: text/html; charset=utf-8\n",
 
-     201,
-     HttpVersion(1, 1)},
+     HttpVersion(1, 1), 201, ""},
     {// Normalize bad status line.
-
      "SCREWED_UP_STATUS_LINE\n"
      "Content-TYPE: text/html; charset=utf-8\n",
 
      "HTTP/1.0 200 OK\n"
      "Content-TYPE: text/html; charset=utf-8\n",
 
-     200,
-     HttpVersion(1, 0)},
-    {// Normalize invalid status code.
+     HttpVersion(1, 0), 200, "OK"},
+    {// Normalize bad status line.
+     "Foo bar.",
 
+     "HTTP/1.0 200\n",
+
+     HttpVersion(1, 0), 200, ""},
+    {// Normalize invalid status code.
      "HTTP/1.1 -1  Unknown\n",
 
      "HTTP/1.1 200\n",
 
-     200,
-     HttpVersion(1, 1)},
+     HttpVersion(1, 1), 200, ""},
     {// Normalize empty header.
-
      "",
 
      "HTTP/1.0 200 OK\n",
 
-     200,
-     HttpVersion(1, 0)},
+     HttpVersion(1, 0), 200, "OK"},
     {// Normalize headers that start with a colon.
-
      "HTTP/1.1    202   Accepted  \n"
      "foo: bar\n"
      ": a \n"
@@ -227,10 +221,8 @@
      "foo: bar\n"
      "baz: blat\n",
 
-     202,
-     HttpVersion(1, 1)},
+     HttpVersion(1, 1), 202, "Accepted"},
     {// Normalize headers that end with a colon.
-
      "HTTP/1.1    202   Accepted  \n"
      "foo:   \n"
      "bar:\n"
@@ -243,18 +235,14 @@
      "baz: blat\n"
      "zip: \n",
 
-     202,
-     HttpVersion(1, 1)},
+     HttpVersion(1, 1), 202, "Accepted"},
     {// Normalize whitespace headers.
-
      "\n   \n",
 
      "HTTP/1.0 200 OK\n",
 
-     200,
-     HttpVersion(1, 0)},
+     HttpVersion(1, 0), 200, "OK"},
     {// Consolidate Set-Cookie headers.
-
      "HTTP/1.1 200 OK\n"
      "Set-Cookie: x=1\n"
      "Set-Cookie: y=2\n",
@@ -262,27 +250,22 @@
      "HTTP/1.1 200 OK\n"
      "Set-Cookie: x=1, y=2\n",
 
-     200,
-     HttpVersion(1, 1)},
+     HttpVersion(1, 1), 200, "OK"},
+    {// Consolidate cache-control headers.
+     "HTTP/1.1 200 OK\n"
+     "Cache-control: private\n"
+     "cache-Control: no-store\n",
+
+     "HTTP/1.1 200 OK\n"
+     "Cache-control: private, no-store\n",
+
+     HttpVersion(1, 1), 200, "OK"},
 };
 
 INSTANTIATE_TEST_CASE_P(HttpResponseHeaders,
                         CommonHttpResponseHeadersTest,
                         testing::ValuesIn(response_headers_tests));
 
-TEST(HttpResponseHeadersTest, GetNormalizedHeader) {
-  std::string headers =
-      "HTTP/1.1 200 OK\n"
-      "Cache-control: private\n"
-      "cache-Control: no-store\n";
-  HeadersToRaw(&headers);
-  scoped_refptr<HttpResponseHeaders> parsed(new HttpResponseHeaders(headers));
-
-  std::string value;
-  EXPECT_TRUE(parsed->GetNormalizedHeader("cache-control", &value));
-  EXPECT_EQ("private, no-store", value);
-}
-
 struct PersistData {
   HttpResponseHeaders::PersistOptions options;
   const char* raw_headers;
@@ -1651,37 +1634,6 @@
                         HasStrongValidatorsTest,
                         testing::ValuesIn(strong_validators_tests));
 
-TEST(HttpResponseHeadersTest, GetStatusText) {
-  std::string headers("HTTP/1.1 404 Not Found");
-  HeadersToRaw(&headers);
-  scoped_refptr<HttpResponseHeaders> parsed(new HttpResponseHeaders(headers));
-  EXPECT_EQ(std::string("Not Found"), parsed->GetStatusText());
-}
-
-TEST(HttpResponseHeadersTest, GetStatusTextMissing) {
-  std::string headers("HTTP/1.1 404");
-  HeadersToRaw(&headers);
-  scoped_refptr<HttpResponseHeaders> parsed(new HttpResponseHeaders(headers));
-  EXPECT_EQ(std::string("HTTP/1.1 404"), parsed->GetStatusLine());
-  EXPECT_TRUE(parsed->GetStatusText().empty());
-}
-
-TEST(HttpResponseHeadersTest, GetStatusTextMultiSpace) {
-  std::string headers("HTTP/1.0     404     Not   Found");
-  HeadersToRaw(&headers);
-  scoped_refptr<HttpResponseHeaders> parsed(new HttpResponseHeaders(headers));
-  EXPECT_EQ(std::string("Not   Found"), parsed->GetStatusText());
-}
-
-TEST(HttpResponseHeadersTest, GetStatusBadStatusLine) {
-  std::string headers("Foo bar.");
-  HeadersToRaw(&headers);
-  scoped_refptr<HttpResponseHeaders> parsed(new HttpResponseHeaders(headers));
-  // The bad status line should be rewritten.
-  EXPECT_EQ(std::string("HTTP/1.0 200"), parsed->GetStatusLine());
-  EXPECT_TRUE(parsed->GetStatusText().empty());
-}
-
 struct AddHeaderTestData {
   const char* orig_headers;
   const char* new_header;
diff --git a/net/http/http_security_headers.cc b/net/http/http_security_headers.cc
index b99b206..ecb8e57 100644
--- a/net/http/http_security_headers.cc
+++ b/net/http/http_security_headers.cc
@@ -2,8 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <limits>
+
 #include "base/base64.h"
-#include "base/basictypes.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_piece.h"
 #include "base/strings/string_tokenizer.h"
@@ -18,36 +19,36 @@
 
 enum MaxAgeParsing { REQUIRE_MAX_AGE, DO_NOT_REQUIRE_MAX_AGE };
 
-static_assert(kMaxHSTSAgeSecs <= kuint32max, "kMaxHSTSAgeSecs too large");
+static_assert(kMaxHSTSAgeSecs <= UINT32_MAX, "kMaxHSTSAgeSecs too large");
 
 // MaxAgeToInt converts a string representation of a "whole number" of
-// seconds into a uint32. The string may contain an arbitrarily large number,
+// seconds into a uint32_t. The string may contain an arbitrarily large number,
 // which will be clipped to kMaxHSTSAgeSecs and which is guaranteed to fit
 // within a 32-bit unsigned integer. False is returned on any parse error.
 bool MaxAgeToInt(std::string::const_iterator begin,
                  std::string::const_iterator end,
-                 uint32* result) {
+                 uint32_t* result) {
   const base::StringPiece s(begin, end);
   if (s.empty())
     return false;
 
-  int64 i = 0;
+  int64_t i = 0;
 
-  // Return false on any StringToInt64 parse errors *except* for
-  // int64 overflow. StringToInt64 is used, rather than StringToUint64,
-  // in order to properly handle and reject negative numbers
-  // (StringToUint64 does not return false on negative numbers).
-  // For values too large to be stored in an int64, StringToInt64 will
-  // return false with i set to kint64max, so this case is detected
-  // by the immediately following if-statement and allowed to fall
-  // through so that i gets clipped to kMaxHSTSAgeSecs.
-  if (!base::StringToInt64(s, &i) && i != kint64max)
+  // Return false on any StringToInt64 parse errors *except* for int64_t
+  // overflow. StringToInt64 is used, rather than StringToUint64, in order to
+  // properly handle and reject negative numbers (StringToUint64 does not return
+  // false on negative numbers). For values too large to be stored in an
+  // int64_t, StringToInt64 will return false with i set to
+  // std::numeric_limits<int64_t>::max(), so this case is detected by the
+  // immediately following if-statement and allowed to fall through so that i
+  // gets clipped to kMaxHSTSAgeSecs.
+  if (!base::StringToInt64(s, &i) && i != std::numeric_limits<int64_t>::max())
     return false;
   if (i < 0)
     return false;
   if (i > kMaxHSTSAgeSecs)
     i = kMaxHSTSAgeSecs;
-  *result = (uint32)i;
+  *result = (uint32_t)i;
   return true;
 }
 
@@ -128,7 +129,7 @@
                          GURL* report_uri) {
   bool parsed_max_age = false;
   bool include_subdomains_candidate = false;
-  uint32 max_age_candidate = 0;
+  uint32_t max_age_candidate = 0;
   GURL parsed_report_uri;
   HashValueVector pins;
   bool require_max_age = max_age_status == REQUIRE_MAX_AGE;
@@ -224,7 +225,7 @@
 bool ParseHSTSHeader(const std::string& value,
                      base::TimeDelta* max_age,
                      bool* include_subdomains) {
-  uint32 max_age_candidate = 0;
+  uint32_t max_age_candidate = 0;
   bool include_subdomains_candidate = false;
 
   // We must see max-age exactly once.
diff --git a/net/http/http_security_headers.h b/net/http/http_security_headers.h
index f54df69..af90430 100644
--- a/net/http/http_security_headers.h
+++ b/net/http/http_security_headers.h
@@ -5,9 +5,10 @@
 #ifndef NET_HTTP_HTTP_SECURITY_HEADERS_H_
 #define NET_HTTP_HTTP_SECURITY_HEADERS_H_
 
+#include <stdint.h>
+
 #include <string>
 
-#include "base/basictypes.h"
 #include "base/time/time.h"
 #include "base/values.h"
 #include "net/base/hash_value.h"
@@ -17,7 +18,7 @@
 
 namespace net {
 
-const int64 kMaxHSTSAgeSecs = 86400 * 365;  // 1 year
+const int64_t kMaxHSTSAgeSecs = 86400 * 365;  // 1 year
 
 // Parses |value| as a Strict-Transport-Security header value. If successful,
 // returns true and sets |*max_age| and |*include_subdomains|.
diff --git a/net/http/http_stream_parser.cc b/net/http/http_stream_parser.cc
index 9ddae48..4e4b6b6 100644
--- a/net/http/http_stream_parser.cc
+++ b/net/http/http_stream_parser.cc
@@ -1078,7 +1078,7 @@
     return false;
   if (!response_->headers || !response_->headers->IsKeepAlive())
     return false;
-  return connection_->socket() && connection_->socket()->IsConnectedAndIdle();
+  return connection_->socket() && connection_->socket()->IsConnected();
 }
 
 void HttpStreamParser::GetSSLInfo(SSLInfo* ssl_info) {
diff --git a/net/http/http_stream_parser.h b/net/http/http_stream_parser.h
index f56e7de..f8700c4 100644
--- a/net/http/http_stream_parser.h
+++ b/net/http/http_stream_parser.h
@@ -79,7 +79,8 @@
   // The connection can be reused if:
   // * It's still connected.
   // * The response headers indicate the connection can be kept alive.
-  // * The end of the response can be found.
+  // * The end of the response can be found, though it may not have yet been
+  //     received.
   //
   // Note that if response headers have yet to be received, this will return
   // false.
diff --git a/net/http/transport_security_state_static.certs b/net/http/transport_security_state_static.certs
index 012b352..9d8f2a6c 100644
--- a/net/http/transport_security_state_static.certs
+++ b/net/http/transport_security_state_static.certs
@@ -7,7 +7,8 @@
 # details.
 
 # Each entry consists of a line containing the name of the pin followed either
-# by a hash in the format "sha256/" + base64(hash), or a PEM encoded certificate.
+# by a hash in the format "sha256/" + base64(hash), a PEM encoded certificate,
+# or a PEM encoded public key.
 
 TestSPKI
 sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
diff --git a/net/net.gyp b/net/net.gyp
index f4c9894e2..32dbf4cc 100644
--- a/net/net.gyp
+++ b/net/net.gyp
@@ -527,6 +527,7 @@
         'cookies/cookie_store_test_callbacks.h',
         'cookies/cookie_store_test_helpers.cc',
         'cookies/cookie_store_test_helpers.h',
+        'cookies/cookie_store_unittest.h',
         'disk_cache/disk_cache_test_base.cc',
         'disk_cache/disk_cache_test_base.h',
         'disk_cache/disk_cache_test_util.cc',
diff --git a/net/net.gypi b/net/net.gypi
index 9d5c3c5..e38f2e33 100644
--- a/net/net.gypi
+++ b/net/net.gypi
@@ -30,6 +30,8 @@
       'base/io_buffer.h',
       'base/ip_address_number.cc',
       'base/ip_address_number.h',
+      'base/ip_address.cc',
+      'base/ip_address.h',
       'base/ip_endpoint.cc',
       'base/ip_endpoint.h',
       'base/load_timing_info.cc',
@@ -1290,6 +1292,7 @@
       'base/host_port_pair_unittest.cc',
       'base/int128_unittest.cc',
       'base/ip_address_number_unittest.cc',
+      'base/ip_address_unittest.cc',
       'base/ip_endpoint_unittest.cc',
       'base/ip_pattern_unittest.cc',
       'base/keygen_handler_unittest.cc',
@@ -1353,7 +1356,6 @@
       'cookies/canonical_cookie_unittest.cc',
       'cookies/cookie_constants_unittest.cc',
       'cookies/cookie_monster_unittest.cc',
-      'cookies/cookie_store_unittest.h',
       'cookies/cookie_util_unittest.cc',
       'cookies/parsed_cookie_unittest.cc',
       'der/input_unittest.cc',
diff --git a/net/proxy/multi_threaded_proxy_resolver.cc b/net/proxy/multi_threaded_proxy_resolver.cc
index 7f03bbf..e03eb28 100644
--- a/net/proxy/multi_threaded_proxy_resolver.cc
+++ b/net/proxy/multi_threaded_proxy_resolver.cc
@@ -5,6 +5,7 @@
 #include "net/proxy/multi_threaded_proxy_resolver.h"
 
 #include <deque>
+#include <utility>
 #include <vector>
 
 #include "base/bind.h"
@@ -576,8 +577,8 @@
     int error = OK;
     if (executor->resolver()) {
       resolver_out_->reset(new MultiThreadedProxyResolver(
-          resolver_factory_.Pass(), max_num_threads_, script_data_.Pass(),
-          executor_));
+          std::move(resolver_factory_), max_num_threads_,
+          std::move(script_data_), executor_));
     } else {
       error = ERR_PAC_SCRIPT_FAILED;
       executor_->Destroy();
diff --git a/net/quic/crypto/quic_crypto_client_config_test.cc b/net/quic/crypto/quic_crypto_client_config_test.cc
index 238011f..418f6c4 100644
--- a/net/quic/crypto/quic_crypto_client_config_test.cc
+++ b/net/quic/crypto/quic_crypto_client_config_test.cc
@@ -346,43 +346,9 @@
   EXPECT_EQ(2u, cleared_cache->generation_counter());
 }
 
-// Creates a minimal dummy reject message that will pass the client-config
-// validation tests.
-void FillInDummyReject(CryptoHandshakeMessage* rej, bool reject_is_stateless) {
-  if (reject_is_stateless) {
-    rej->set_tag(kSREJ);
-  } else {
-    rej->set_tag(kREJ);
-  }
-
-  // Minimum SCFG that passes config validation checks.
-  // clang-format off
-  unsigned char scfg[] = {
-    // SCFG
-    0x53, 0x43, 0x46, 0x47,
-    // num entries
-    0x01, 0x00,
-    // padding
-    0x00, 0x00,
-    // EXPY
-    0x45, 0x58, 0x50, 0x59,
-    // EXPY end offset
-    0x08, 0x00, 0x00, 0x00,
-    // Value
-    '1',  '2',  '3',  '4',
-    '5',  '6',  '7',  '8'
-  };
-  // clang-format on
-  rej->SetValue(kSCFG, scfg);
-  rej->SetStringPiece(kServerNonceTag, "SERVER_NONCE");
-  vector<QuicTag> reject_reasons;
-  reject_reasons.push_back(CLIENT_NONCE_INVALID_FAILURE);
-  rej->SetVector(kRREJ, reject_reasons);
-}
-
 TEST(QuicCryptoClientConfigTest, ProcessReject) {
   CryptoHandshakeMessage rej;
-  FillInDummyReject(&rej, /* stateless */ false);
+  CryptoTestUtils::FillInDummyReject(&rej, /* stateless */ false);
 
   // Now process the rejection.
   QuicCryptoClientConfig::CachedState cached;
@@ -400,7 +366,7 @@
 TEST(QuicCryptoClientConfigTest, ProcessStatelessReject) {
   // Create a dummy reject message and mark it as stateless.
   CryptoHandshakeMessage rej;
-  FillInDummyReject(&rej, /* stateless */ true);
+  CryptoTestUtils::FillInDummyReject(&rej, /* stateless */ true);
   const QuicConnectionId kConnectionId = 0xdeadbeef;
   const string server_nonce = "SERVER_NONCE";
   rej.SetValue(kRCID, kConnectionId);
@@ -424,7 +390,7 @@
   // Create a dummy reject message and mark it as stateless.  Do not
   // add an server-designated connection-id.
   CryptoHandshakeMessage rej;
-  FillInDummyReject(&rej, /* stateless */ true);
+  CryptoTestUtils::FillInDummyReject(&rej, /* stateless */ true);
 
   // Now process the rejection.
   QuicCryptoClientConfig::CachedState cached;
diff --git a/net/quic/quic_crypto_client_stream.cc b/net/quic/quic_crypto_client_stream.cc
index 2c2a98c..668cff9 100644
--- a/net/quic/quic_crypto_client_stream.cc
+++ b/net/quic/quic_crypto_client_stream.cc
@@ -255,6 +255,7 @@
 
   // Send the client hello in plaintext.
   session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_NONE);
+  encryption_established_ = false;
   if (num_client_hellos_ > kMaxClientHellos) {
     CloseConnection(QUIC_CRYPTO_TOO_MANY_REJECTS);
     return;
diff --git a/net/quic/quic_flags.cc b/net/quic/quic_flags.cc
index b63a0e5..8d45f32e 100644
--- a/net/quic/quic_flags.cc
+++ b/net/quic/quic_flags.cc
@@ -118,3 +118,7 @@
 // If true, allow each quic stream to write 16k blocks rather than doing a round
 // robin of one packet per session when ack clocked or paced.
 bool FLAGS_quic_batch_writes = true;
+
+// If true, QUIC sessions will write block streams that attempt to write
+// unencrypted data.
+bool FLAGS_quic_block_unencrypted_writes = true;
diff --git a/net/quic/quic_flags.h b/net/quic/quic_flags.h
index 8f4ee24..78c5c50 100644
--- a/net/quic/quic_flags.h
+++ b/net/quic/quic_flags.h
@@ -38,4 +38,6 @@
 NET_EXPORT_PRIVATE extern bool FLAGS_quic_set_client_hello_cb_nullptr;
 NET_EXPORT_PRIVATE extern bool FLAGS_quic_track_single_retransmission;
 NET_EXPORT_PRIVATE extern bool FLAGS_quic_batch_writes;
+NET_EXPORT_PRIVATE extern bool FLAGS_quic_block_unencrypted_writes;
+
 #endif  // NET_QUIC_QUIC_FLAGS_H_
diff --git a/net/quic/quic_session.cc b/net/quic/quic_session.cc
index fc8e42f..ca11f6ba 100644
--- a/net/quic/quic_session.cc
+++ b/net/quic/quic_session.cc
@@ -292,6 +292,12 @@
     bool fin,
     FecProtection fec_protection,
     QuicAckListenerInterface* ack_notifier_delegate) {
+  if (FLAGS_quic_block_unencrypted_writes && !IsEncryptionEstablished() &&
+      id != kCryptoStreamId) {
+    // Do not let streams write without encryption. The calling stream will end
+    // up write blocked until OnCanWrite is next called.
+    return QuicConsumedData(0, false);
+  }
   QuicConsumedData data = connection_->SendStreamData(
       id, iov, offset, fin, fec_protection, ack_notifier_delegate);
   write_blocked_streams_.UpdateBytesForStream(id, data.bytes_consumed);
@@ -517,12 +523,20 @@
     // TODO(satyamshekhar): Move the logic of setting the encrypter/decrypter
     // to QuicSession since it is the glue.
     case ENCRYPTION_FIRST_ESTABLISHED:
+      // Given any streams blocked by encryption a chance to write.
+      if (FLAGS_quic_block_unencrypted_writes) {
+        OnCanWrite();
+      }
       break;
 
     case ENCRYPTION_REESTABLISHED:
       // Retransmit originally packets that were sent, since they can't be
       // decrypted by the peer.
       connection_->RetransmitUnackedPackets(ALL_INITIAL_RETRANSMISSION);
+      // Given any streams blocked by encryption a chance to write.
+      if (FLAGS_quic_block_unencrypted_writes) {
+        OnCanWrite();
+      }
       break;
 
     case HANDSHAKE_CONFIRMED:
diff --git a/net/quic/quic_session_test.cc b/net/quic/quic_session_test.cc
index 35473da..7299c40 100644
--- a/net/quic/quic_session_test.cc
+++ b/net/quic/quic_session_test.cc
@@ -505,6 +505,10 @@
 }
 
 TEST_P(QuicSessionTestServer, OnCanWriteBundlesStreams) {
+  // Encryption needs to be established before data can be sent.
+  CryptoHandshakeMessage msg;
+  session_.GetCryptoStream()->OnHandshakeMessage(msg);
+
   // Drive congestion control manually.
   MockSendAlgorithm* send_algorithm = new StrictMock<MockSendAlgorithm>;
   QuicConnectionPeer::SetSendAlgorithm(session_.connection(), send_algorithm);
diff --git a/net/quic/test_tools/crypto_test_utils.cc b/net/quic/test_tools/crypto_test_utils.cc
index 7c3e8b9..ed34502 100644
--- a/net/quic/test_tools/crypto_test_utils.cc
+++ b/net/quic/test_tools/crypto_test_utils.cc
@@ -355,6 +355,40 @@
   return new class MockCommonCertSets(cert, hash, index);
 }
 
+// static
+void CryptoTestUtils::FillInDummyReject(CryptoHandshakeMessage* rej,
+                                        bool reject_is_stateless) {
+  if (reject_is_stateless) {
+    rej->set_tag(kSREJ);
+  } else {
+    rej->set_tag(kREJ);
+  }
+
+  // Minimum SCFG that passes config validation checks.
+  // clang-format off
+  unsigned char scfg[] = {
+    // SCFG
+    0x53, 0x43, 0x46, 0x47,
+    // num entries
+    0x01, 0x00,
+    // padding
+    0x00, 0x00,
+    // EXPY
+    0x45, 0x58, 0x50, 0x59,
+    // EXPY end offset
+    0x08, 0x00, 0x00, 0x00,
+    // Value
+    '1',  '2',  '3',  '4',
+    '5',  '6',  '7',  '8'
+  };
+  // clang-format on
+  rej->SetValue(kSCFG, scfg);
+  rej->SetStringPiece(kServerNonceTag, "SERVER_NONCE");
+  vector<QuicTag> reject_reasons;
+  reject_reasons.push_back(CLIENT_NONCE_INVALID_FAILURE);
+  rej->SetVector(kRREJ, reject_reasons);
+}
+
 void CryptoTestUtils::CompareClientAndServerKeys(
     QuicCryptoClientStream* client,
     QuicCryptoServerStream* server) {
diff --git a/net/quic/test_tools/crypto_test_utils.h b/net/quic/test_tools/crypto_test_utils.h
index b823c61..56b07507 100644
--- a/net/quic/test_tools/crypto_test_utils.h
+++ b/net/quic/test_tools/crypto_test_utils.h
@@ -156,6 +156,12 @@
                                             uint64 hash,
                                             uint32 index);
 
+  // Creates a minimal dummy reject message that will pass the client-config
+  // validation tests. This will include a server config, but no certs, proof
+  // source address token, or server nonce.
+  static void FillInDummyReject(CryptoHandshakeMessage* rej,
+                                bool reject_is_stateless);
+
   // ParseTag returns a QuicTag from parsing |tagstr|. |tagstr| may either be
   // in the format "EXMP" (i.e. ASCII format), or "#11223344" (an explicit hex
   // format). It CHECK fails if there's a parse error.
diff --git a/net/quic/test_tools/quic_packet_creator_peer.cc b/net/quic/test_tools/quic_packet_creator_peer.cc
index 0d20315..a310121f 100644
--- a/net/quic/test_tools/quic_packet_creator_peer.cc
+++ b/net/quic/test_tools/quic_packet_creator_peer.cc
@@ -117,5 +117,11 @@
   return creator->rtt_multiplier_for_fec_timeout_;
 }
 
+// static
+EncryptionLevel QuicPacketCreatorPeer::GetEncryptionLevel(
+    QuicPacketCreator* creator) {
+  return creator->encryption_level_;
+}
+
 }  // namespace test
 }  // namespace net
diff --git a/net/quic/test_tools/quic_packet_creator_peer.h b/net/quic/test_tools/quic_packet_creator_peer.h
index ca62f36..b871c40 100644
--- a/net/quic/test_tools/quic_packet_creator_peer.h
+++ b/net/quic/test_tools/quic_packet_creator_peer.h
@@ -51,6 +51,7 @@
   static QuicTime::Delta GetFecTimeout(QuicPacketCreator* creator);
   // TODO(rtenneti): Delete this code after the 0.25 RTT FEC experiment.
   static float GetRttMultiplierForFecTimeout(QuicPacketCreator* creator);
+  static EncryptionLevel GetEncryptionLevel(QuicPacketCreator* creator);
 
  private:
   DISALLOW_COPY_AND_ASSIGN(QuicPacketCreatorPeer);
diff --git a/net/socket/ssl_client_socket_unittest.cc b/net/socket/ssl_client_socket_unittest.cc
index c048bea..dce9f0a 100644
--- a/net/socket/ssl_client_socket_unittest.cc
+++ b/net/socket/ssl_client_socket_unittest.cc
@@ -690,7 +690,9 @@
   const AddressList& addr() const { return addr_; }
 
   // The SpawnedTestServer object, after calling StartTestServer().
-  const SpawnedTestServer* test_server() const { return test_server_.get(); }
+  const SpawnedTestServer* spawned_test_server() const {
+    return spawned_test_server_.get();
+  }
 
   void SetCTVerifier(CTVerifier* ct_verifier) {
     context_.cert_transparency_verifier = ct_verifier;
@@ -699,14 +701,14 @@
   // Starts the test server with SSL configuration |ssl_options|. Returns true
   // on success.
   bool StartTestServer(const SpawnedTestServer::SSLOptions& ssl_options) {
-    test_server_.reset(new SpawnedTestServer(
+    spawned_test_server_.reset(new SpawnedTestServer(
         SpawnedTestServer::TYPE_HTTPS, ssl_options, base::FilePath()));
-    if (!test_server_->Start()) {
+    if (!spawned_test_server_->Start()) {
       LOG(ERROR) << "Could not start SpawnedTestServer";
       return false;
     }
 
-    if (!test_server_->GetAddressList(&addr_)) {
+    if (!spawned_test_server_->GetAddressList(&addr_)) {
       LOG(ERROR) << "Could not get SpawnedTestServer address list";
       return false;
     }
@@ -741,8 +743,8 @@
       return false;
     }
 
-    sock_ = CreateSSLClientSocket(transport.Pass(),
-                                  test_server_->host_port_pair(), ssl_config);
+    sock_ = CreateSSLClientSocket(
+        transport.Pass(), spawned_test_server_->host_port_pair(), ssl_config);
     EXPECT_FALSE(sock_->IsConnected());
 
     *result = callback_.GetResult(sock_->Connect(callback_.callback()));
@@ -757,7 +759,7 @@
   TestNetLog log_;
 
  private:
-  scoped_ptr<SpawnedTestServer> test_server_;
+  scoped_ptr<SpawnedTestServer> spawned_test_server_;
   TestCompletionCallback callback_;
   AddressList addr_;
 };
@@ -769,13 +771,13 @@
   // the SSLCertRequestInfo reported by the socket.
   scoped_refptr<SSLCertRequestInfo> GetCertRequest(
       SpawnedTestServer::SSLOptions ssl_options) {
-    SpawnedTestServer test_server(
-        SpawnedTestServer::TYPE_HTTPS, ssl_options, base::FilePath());
-    if (!test_server.Start())
+    SpawnedTestServer spawned_test_server(SpawnedTestServer::TYPE_HTTPS,
+                                          ssl_options, base::FilePath());
+    if (!spawned_test_server.Start())
       return NULL;
 
     AddressList addr;
-    if (!test_server.GetAddressList(&addr))
+    if (!spawned_test_server.GetAddressList(&addr))
       return NULL;
 
     TestCompletionCallback callback;
@@ -786,7 +788,7 @@
     EXPECT_EQ(OK, rv);
 
     scoped_ptr<SSLClientSocket> sock(CreateSSLClientSocket(
-        transport.Pass(), test_server.host_port_pair(), SSLConfig()));
+        transport.Pass(), spawned_test_server.host_port_pair(), SSLConfig()));
     EXPECT_FALSE(sock->IsConnected());
 
     rv = callback.GetResult(sock->Connect(callback.callback()));
@@ -796,8 +798,8 @@
     sock->GetSSLCertRequestInfo(request_info.get());
     sock->Disconnect();
     EXPECT_FALSE(sock->IsConnected());
-    EXPECT_TRUE(
-        test_server.host_port_pair().Equals(request_info->host_and_port));
+    EXPECT_TRUE(spawned_test_server.host_port_pair().Equals(
+        request_info->host_and_port));
 
     return request_info;
   }
@@ -823,7 +825,7 @@
       TestCompletionCallback* callback,
       FakeBlockingStreamSocket** out_raw_transport,
       scoped_ptr<SSLClientSocket>* out_sock) {
-    CHECK(test_server());
+    CHECK(spawned_test_server());
 
     scoped_ptr<StreamSocket> real_transport(
         new TCPClientSocket(addr(), NULL, NetLog::Source()));
@@ -834,7 +836,8 @@
 
     FakeBlockingStreamSocket* raw_transport = transport.get();
     scoped_ptr<SSLClientSocket> sock = CreateSSLClientSocket(
-        transport.Pass(), test_server()->host_port_pair(), client_config);
+        transport.Pass(), spawned_test_server()->host_port_pair(),
+        client_config);
 
     // Connect. Stop before the client processes the first server leg
     // (ServerHello, etc.)
@@ -949,7 +952,7 @@
   EXPECT_EQ(OK, rv);
 
   scoped_ptr<SSLClientSocket> sock(CreateSSLClientSocket(
-      transport.Pass(), test_server()->host_port_pair(), SSLConfig()));
+      transport.Pass(), spawned_test_server()->host_port_pair(), SSLConfig()));
 
   EXPECT_FALSE(sock->IsConnected());
 
@@ -1096,7 +1099,7 @@
   EXPECT_EQ(OK, rv);
 
   scoped_ptr<SSLClientSocket> sock(CreateSSLClientSocket(
-      transport.Pass(), test_server()->host_port_pair(), SSLConfig()));
+      transport.Pass(), spawned_test_server()->host_port_pair(), SSLConfig()));
   EXPECT_EQ(0, sock->GetTotalReceivedBytes());
 
   rv = callback.GetResult(sock->Connect(callback.callback()));
@@ -1157,7 +1160,7 @@
 
   SynchronousErrorStreamSocket* raw_transport = transport.get();
   scoped_ptr<SSLClientSocket> sock(CreateSSLClientSocket(
-      transport.Pass(), test_server()->host_port_pair(), ssl_config));
+      transport.Pass(), spawned_test_server()->host_port_pair(), ssl_config));
 
   raw_transport->SetNextWriteError(ERR_CONNECTION_RESET);
 
@@ -1187,7 +1190,7 @@
 
   SynchronousErrorStreamSocket* raw_transport = transport.get();
   scoped_ptr<SSLClientSocket> sock(CreateSSLClientSocket(
-      transport.Pass(), test_server()->host_port_pair(), ssl_config));
+      transport.Pass(), spawned_test_server()->host_port_pair(), ssl_config));
 
   rv = callback.GetResult(sock->Connect(callback.callback()));
   EXPECT_EQ(OK, rv);
@@ -1241,7 +1244,7 @@
   ssl_config.false_start_enabled = false;
 
   scoped_ptr<SSLClientSocket> sock(CreateSSLClientSocket(
-      transport.Pass(), test_server()->host_port_pair(), ssl_config));
+      transport.Pass(), spawned_test_server()->host_port_pair(), ssl_config));
 
   rv = callback.GetResult(sock->Connect(callback.callback()));
   EXPECT_EQ(OK, rv);
@@ -1307,7 +1310,8 @@
   ssl_config.false_start_enabled = false;
 
   scoped_ptr<SSLClientSocket> sock(CreateSSLClientSocket(
-      counting_socket.Pass(), test_server()->host_port_pair(), ssl_config));
+      counting_socket.Pass(), spawned_test_server()->host_port_pair(),
+      ssl_config));
 
   rv = callback.GetResult(sock->Connect(callback.callback()));
   ASSERT_EQ(OK, rv);
@@ -1407,7 +1411,7 @@
   ssl_config.false_start_enabled = false;
 
   scoped_ptr<SSLClientSocket> sock = CreateSSLClientSocket(
-      transport.Pass(), test_server()->host_port_pair(), ssl_config);
+      transport.Pass(), spawned_test_server()->host_port_pair(), ssl_config);
 
   rv = callback.GetResult(sock->Connect(callback.callback()));
   EXPECT_EQ(OK, rv);
@@ -1515,7 +1519,7 @@
   ssl_config.false_start_enabled = false;
 
   scoped_ptr<SSLClientSocket> sock(CreateSSLClientSocket(
-      transport.Pass(), test_server()->host_port_pair(), ssl_config));
+      transport.Pass(), spawned_test_server()->host_port_pair(), ssl_config));
 
   rv = callback.GetResult(sock->Connect(callback.callback()));
   EXPECT_EQ(OK, rv);
@@ -1601,7 +1605,7 @@
 
   SynchronousErrorStreamSocket* raw_transport = transport.get();
   scoped_ptr<SSLClientSocket> sock(CreateSSLClientSocket(
-      transport.Pass(), test_server()->host_port_pair(), SSLConfig()));
+      transport.Pass(), spawned_test_server()->host_port_pair(), SSLConfig()));
 
   raw_transport->SetNextReadError(0);
 
@@ -1630,7 +1634,7 @@
 
   SynchronousErrorStreamSocket* raw_transport = transport.get();
   scoped_ptr<SSLClientSocket> sock(CreateSSLClientSocket(
-      transport.Pass(), test_server()->host_port_pair(), ssl_config));
+      transport.Pass(), spawned_test_server()->host_port_pair(), ssl_config));
 
   rv = callback.GetResult(sock->Connect(callback.callback()));
   EXPECT_EQ(OK, rv);
@@ -1665,7 +1669,7 @@
   ssl_config.false_start_enabled = false;
 
   scoped_ptr<SSLClientSocket> sock(CreateSSLClientSocket(
-      transport.Pass(), test_server()->host_port_pair(), ssl_config));
+      transport.Pass(), spawned_test_server()->host_port_pair(), ssl_config));
 
   rv = callback.GetResult(sock->Connect(callback.callback()));
   EXPECT_EQ(OK, rv);
@@ -1738,7 +1742,7 @@
   ASSERT_EQ(OK, rv);
 
   scoped_ptr<SSLClientSocket> sock(CreateSSLClientSocket(
-      transport.Pass(), test_server()->host_port_pair(), SSLConfig()));
+      transport.Pass(), spawned_test_server()->host_port_pair(), SSLConfig()));
 
   rv = callback.GetResult(sock->Connect(callback.callback()));
   ASSERT_EQ(OK, rv);
@@ -1805,7 +1809,7 @@
   EXPECT_EQ(OK, rv);
 
   scoped_ptr<SSLClientSocket> sock(CreateSSLClientSocket(
-      transport.Pass(), test_server()->host_port_pair(), SSLConfig()));
+      transport.Pass(), spawned_test_server()->host_port_pair(), SSLConfig()));
 
   rv = callback.GetResult(sock->Connect(callback.callback()));
   EXPECT_EQ(OK, rv);
@@ -1873,7 +1877,7 @@
   EXPECT_EQ(OK, rv);
 
   scoped_ptr<SSLClientSocket> sock(CreateSSLClientSocket(
-      transport.Pass(), test_server()->host_port_pair(), SSLConfig()));
+      transport.Pass(), spawned_test_server()->host_port_pair(), SSLConfig()));
 
   rv = callback.GetResult(sock->Connect(callback.callback()));
   EXPECT_EQ(ERR_SSL_PROTOCOL_ERROR, rv);
@@ -1920,8 +1924,8 @@
   socket_handle->SetSocket(transport.Pass());
 
   scoped_ptr<SSLClientSocket> sock(socket_factory_->CreateSSLClientSocket(
-      socket_handle.Pass(), test_server()->host_port_pair(), SSLConfig(),
-      context_));
+      socket_handle.Pass(), spawned_test_server()->host_port_pair(),
+      SSLConfig(), context_));
 
   EXPECT_FALSE(sock->IsConnected());
   rv = callback.GetResult(sock->Connect(callback.callback()));
@@ -2356,7 +2360,7 @@
   ASSERT_EQ(OK, callback.GetResult(transport->Connect(callback.callback())));
 
   scoped_ptr<SSLClientSocket> sock(CreateSSLClientSocket(
-      transport.Pass(), test_server()->host_port_pair(), SSLConfig()));
+      transport.Pass(), spawned_test_server()->host_port_pair(), SSLConfig()));
   ASSERT_EQ(OK, callback.GetResult(sock->Connect(callback.callback())));
 
   // Block any application data from reaching the network.
diff --git a/net/spdy/hpack/hpack_huffman_table_test.cc b/net/spdy/hpack/hpack_huffman_table_test.cc
index a48ccb4..fe2420e 100644
--- a/net/spdy/hpack/hpack_huffman_table_test.cc
+++ b/net/spdy/hpack/hpack_huffman_table_test.cc
@@ -4,7 +4,10 @@
 
 #include "net/spdy/hpack/hpack_huffman_table.h"
 
+#include <stdint.h>
+
 #include <bitset>
+#include <limits>
 #include <string>
 
 #include "base/logging.h"
@@ -32,8 +35,8 @@
   explicit HpackHuffmanTablePeer(const HpackHuffmanTable& table)
       : table_(table) {}
 
-  const std::vector<uint32>& code_by_id() const { return table_.code_by_id_; }
-  const std::vector<uint8>& length_by_id() const {
+  const std::vector<uint32_t>& code_by_id() const { return table_.code_by_id_; }
+  const std::vector<uint8_t>& length_by_id() const {
     return table_.length_by_id_;
   }
   const std::vector<DecodeTable>& decode_tables() const {
@@ -43,7 +46,7 @@
     // Cast to match signed-ness of bits8().
     return static_cast<char>(table_.pad_bits_);
   }
-  uint16 failed_symbol_id() const { return table_.failed_symbol_id_; }
+  uint16_t failed_symbol_id() const { return table_.failed_symbol_id_; }
   std::vector<DecodeEntry> decode_entries(const DecodeTable& decode_table) {
     std::vector<DecodeEntry>::const_iterator begin =
         table_.decode_entries_.begin() + decode_table.entries_offset;
@@ -82,7 +85,7 @@
          lhs.length == rhs.length && lhs.symbol_id == rhs.symbol_id;
 }
 
-uint32 bits32(const string& bitstring) {
+uint32_t bits32(const string& bitstring) {
   return std::bitset<32>(bitstring).to_ulong();
 }
 char bits8(const string& bitstring) {
@@ -239,7 +242,8 @@
   EXPECT_EQ(expect, buffer_in);
 
   string buffer_out;
-  HpackInputStream input_stream(kuint32max, buffer_in);
+  HpackInputStream input_stream(std::numeric_limits<uint32_t>::max(),
+                                buffer_in);
   EXPECT_TRUE(table_.DecodeString(&input_stream, input.size(), &buffer_out));
   EXPECT_EQ(buffer_out, input);
 }
@@ -304,7 +308,7 @@
     char input_storage[] = {bits8("00010001"), bits8("00110100")};
     StringPiece input(input_storage, arraysize(input_storage));
 
-    HpackInputStream input_stream(kuint32max, input);
+    HpackInputStream input_stream(std::numeric_limits<uint32_t>::max(), input);
     EXPECT_TRUE(table_.DecodeString(&input_stream, capacity, &buffer));
     EXPECT_EQ(buffer, "\x02\x03\x02\x06");
   }
@@ -314,7 +318,7 @@
     char input_storage[] = {bits8("00010001"), bits8("01000111")};
     StringPiece input(input_storage, arraysize(input_storage));
 
-    HpackInputStream input_stream(kuint32max, input);
+    HpackInputStream input_stream(std::numeric_limits<uint32_t>::max(), input);
     EXPECT_FALSE(table_.DecodeString(&input_stream, capacity, &buffer));
     EXPECT_EQ(buffer, "\x02\x03\x02");
   }
@@ -323,7 +327,7 @@
     std::vector<char> input_storage(1 + capacity / 4, '\0');
     StringPiece input(&input_storage[0], input_storage.size());
 
-    HpackInputStream input_stream(kuint32max, input);
+    HpackInputStream input_stream(std::numeric_limits<uint32_t>::max(), input);
     EXPECT_FALSE(table_.DecodeString(&input_stream, capacity, &buffer));
 
     std::vector<char> expected(capacity, '\x02');
@@ -336,7 +340,7 @@
     char input_storage[] = {bits8("10011010"), bits8("01110000")};
     StringPiece input(input_storage, arraysize(input_storage));
 
-    HpackInputStream input_stream(kuint32max, input);
+    HpackInputStream input_stream(std::numeric_limits<uint32_t>::max(), input);
     EXPECT_FALSE(table_.DecodeString(&input_stream, capacity, &buffer));
     EXPECT_EQ(buffer, "\x06");
   }
@@ -361,7 +365,8 @@
   for (size_t i = 0; i != arraysize(test_table); i += 2) {
     const string& encodedFixture(test_table[i]);
     const string& decodedFixture(test_table[i + 1]);
-    HpackInputStream input_stream(kuint32max, encodedFixture);
+    HpackInputStream input_stream(std::numeric_limits<uint32_t>::max(),
+                                  encodedFixture);
 
     EXPECT_TRUE(
         table_.DecodeString(&input_stream, decodedFixture.size(), &buffer));
@@ -392,7 +397,8 @@
   for (size_t i = 0; i != arraysize(test_table); i += 2) {
     const string& encodedFixture(test_table[i]);
     const string& decodedFixture(test_table[i + 1]);
-    HpackInputStream input_stream(kuint32max, encodedFixture);
+    HpackInputStream input_stream(std::numeric_limits<uint32_t>::max(),
+                                  encodedFixture);
 
     EXPECT_TRUE(
         table_.DecodeString(&input_stream, decodedFixture.size(), &buffer));
@@ -414,7 +420,8 @@
     string buffer_in = EncodeString(input);
     string buffer_out;
 
-    HpackInputStream input_stream(kuint32max, buffer_in);
+    HpackInputStream input_stream(std::numeric_limits<uint32_t>::max(),
+                                  buffer_in);
     EXPECT_TRUE(table_.DecodeString(&input_stream, input.size(), &buffer_out));
     EXPECT_EQ(input, buffer_out);
   }
@@ -434,7 +441,8 @@
   string buffer_in = EncodeString(input);
   string buffer_out;
 
-  HpackInputStream input_stream(kuint32max, buffer_in);
+  HpackInputStream input_stream(std::numeric_limits<uint32_t>::max(),
+                                buffer_in);
   EXPECT_TRUE(table_.DecodeString(&input_stream, input.size(), &buffer_out));
   EXPECT_EQ(input, buffer_out);
 }
diff --git a/net/ssl/client_key_store.cc b/net/ssl/client_key_store.cc
index 5001703..87dafec1 100644
--- a/net/ssl/client_key_store.cc
+++ b/net/ssl/client_key_store.cc
@@ -5,6 +5,7 @@
 #include "net/ssl/client_key_store.h"
 
 #include <algorithm>
+#include <utility>
 
 #include "net/cert/x509_certificate.h"
 #include "net/ssl/ssl_private_key.h"
@@ -45,7 +46,7 @@
   for (const auto& provider : providers_) {
     scoped_refptr<SSLPrivateKey> key;
     if (provider->GetCertificateKey(certificate, &key))
-      return key.Pass();
+      return key;
   }
   return nullptr;
 }
diff --git a/net/ssl/ssl_platform_key_task_runner.cc b/net/ssl/ssl_platform_key_task_runner.cc
index 963b6d7..7611d60 100644
--- a/net/ssl/ssl_platform_key_task_runner.cc
+++ b/net/ssl/ssl_platform_key_task_runner.cc
@@ -25,7 +25,7 @@
     LAZY_INSTANCE_INITIALIZER;
 
 scoped_refptr<base::SequencedTaskRunner> GetSSLPlatformKeyTaskRunner() {
-  return g_platform_key_task_runner.Get().task_runner().Pass();
+  return g_platform_key_task_runner.Get().task_runner();
 }
 
 }  // namespace net
diff --git a/net/ssl/threaded_ssl_private_key.cc b/net/ssl/threaded_ssl_private_key.cc
index c96598f..11698620 100644
--- a/net/ssl/threaded_ssl_private_key.cc
+++ b/net/ssl/threaded_ssl_private_key.cc
@@ -5,6 +5,7 @@
 #include "net/ssl/threaded_ssl_private_key.h"
 
 #include <string>
+#include <utility>
 
 #include "base/bind.h"
 #include "base/location.h"
@@ -50,10 +51,9 @@
 ThreadedSSLPrivateKey::ThreadedSSLPrivateKey(
     scoped_ptr<ThreadedSSLPrivateKey::Delegate> delegate,
     scoped_refptr<base::TaskRunner> task_runner)
-    : core_(new Core(delegate.Pass())),
-      task_runner_(task_runner.Pass()),
-      weak_factory_(this) {
-}
+    : core_(new Core(std::move(delegate))),
+      task_runner_(std::move(task_runner)),
+      weak_factory_(this) {}
 
 SSLPrivateKey::Type ThreadedSSLPrivateKey::GetType() {
   return core_->delegate()->GetType();
diff --git a/net/test/embedded_test_server/default_handlers.cc b/net/test/embedded_test_server/default_handlers.cc
index b1fe69d4..f2e1acc3 100644
--- a/net/test/embedded_test_server/default_handlers.cc
+++ b/net/test/embedded_test_server/default_handlers.cc
@@ -623,7 +623,6 @@
   // TODO(svaldez): HandleDownload
   // TODO(svaldez): HandleDownloadFinish
   // TODO(svaldez): HandleZipFile
-  // TODO(svaldez): HandleRangeReset
   // TODO(svaldez): HandleSSLManySmallRecords
   // TODO(svaldez): HandleChunkedServer
   // TODO(svaldez): HandleGetSSLSessionCache
diff --git a/net/tools/quic/quic_client_session_test.cc b/net/tools/quic/quic_client_session_test.cc
index ec0770a..7ee0c16 100644
--- a/net/tools/quic/quic_client_session_test.cc
+++ b/net/tools/quic/quic_client_session_test.cc
@@ -10,6 +10,8 @@
 #include "net/quic/crypto/aes_128_gcm_12_encrypter.h"
 #include "net/quic/quic_flags.h"
 #include "net/quic/test_tools/crypto_test_utils.h"
+#include "net/quic/test_tools/quic_connection_peer.h"
+#include "net/quic/test_tools/quic_packet_creator_peer.h"
 #include "net/quic/test_tools/quic_spdy_session_peer.h"
 #include "net/quic/test_tools/quic_test_utils.h"
 #include "net/tools/quic/quic_spdy_client_stream.h"
@@ -22,6 +24,8 @@
 using net::test::MockConnection;
 using net::test::MockConnectionHelper;
 using net::test::PacketSavingConnection;
+using net::test::QuicConnectionPeer;
+using net::test::QuicPacketCreatorPeer;
 using net::test::QuicSpdySessionPeer;
 using net::test::SupportedVersions;
 using net::test::TestPeerIPAddress;
@@ -44,20 +48,23 @@
     : public ::testing::TestWithParam<QuicVersion> {
  protected:
   ToolsQuicClientSessionTest()
-      : crypto_config_(CryptoTestUtils::ProofVerifierForTesting()),
-        connection_(new PacketSavingConnection(&helper_,
-                                               Perspective::IS_CLIENT,
-                                               SupportedVersions(GetParam()))),
-        session_(new QuicClientSession(
-            DefaultQuicConfig(),
-            connection_,
-            QuicServerId(kServerHostname, kPort, PRIVACY_MODE_DISABLED),
-            &crypto_config_)) {
-    session_->Initialize();
+      : crypto_config_(CryptoTestUtils::ProofVerifierForTesting()) {
+    Initialize();
     // Advance the time, because timers do not like uninitialized times.
     connection_->AdvanceTime(QuicTime::Delta::FromSeconds(1));
   }
 
+  void Initialize() {
+    session_.reset();
+    connection_ = new PacketSavingConnection(&helper_, Perspective::IS_CLIENT,
+                                             SupportedVersions(GetParam()));
+    session_.reset(new QuicClientSession(
+        DefaultQuicConfig(), connection_,
+        QuicServerId(kServerHostname, kPort, PRIVACY_MODE_DISABLED),
+        &crypto_config_));
+    session_->Initialize();
+  }
+
   void CompleteCryptoHandshake() {
     session_->CryptoConnect();
     QuicCryptoClientStream* stream =
@@ -80,6 +87,45 @@
   CompleteCryptoHandshake();
 }
 
+TEST_P(ToolsQuicClientSessionTest, NoEncryptionAfterInitialEncryption) {
+  ValueRestore<bool> old_flag(&FLAGS_quic_block_unencrypted_writes, true);
+  // Complete a handshake in order to prime the crypto config for 0-RTT.
+  CompleteCryptoHandshake();
+
+  // Now create a second session using the same crypto config.
+  Initialize();
+
+  // Starting the handshake should move immediately to encryption
+  // established and will allow streams to be created.
+  session_->CryptoConnect();
+  EXPECT_TRUE(session_->IsEncryptionEstablished());
+  QuicSpdyClientStream* stream = session_->CreateOutgoingDynamicStream();
+  DCHECK_NE(kCryptoStreamId, stream->id());
+  EXPECT_TRUE(stream != nullptr);
+
+  // Process an "inchoate" REJ from the server which will cause
+  // an inchoate CHLO to be sent and will leave the encryption level
+  // at NONE.
+  CryptoHandshakeMessage rej;
+  CryptoTestUtils::FillInDummyReject(&rej, /* stateless */ false);
+  EXPECT_TRUE(session_->IsEncryptionEstablished());
+  session_->GetCryptoStream()->OnHandshakeMessage(rej);
+  EXPECT_FALSE(session_->IsEncryptionEstablished());
+  EXPECT_EQ(ENCRYPTION_NONE,
+            QuicPacketCreatorPeer::GetEncryptionLevel(
+                QuicConnectionPeer::GetPacketCreator(connection_)));
+  // Verify that no new streams may be created.
+  EXPECT_TRUE(session_->CreateOutgoingDynamicStream() == nullptr);
+  // Verify that no data may be send on existing streams.
+  char data[] = "hello world";
+  struct iovec iov = {data, arraysize(data)};
+  QuicIOVector iovector(&iov, 1, iov.iov_len);
+  QuicConsumedData consumed = session_->WritevData(
+      stream->id(), iovector, 0, false, MAY_FEC_PROTECT, nullptr);
+  EXPECT_FALSE(consumed.fin_consumed);
+  EXPECT_EQ(0u, consumed.bytes_consumed);
+}
+
 TEST_P(ToolsQuicClientSessionTest, MaxNumStreamsWithNoFinOrRst) {
   EXPECT_CALL(*connection_, SendRstStream(_, _, _)).Times(AnyNumber());
 
diff --git a/net/tools/testserver/testserver.py b/net/tools/testserver/testserver.py
index 10ade37..1531765 100755
--- a/net/tools/testserver/testserver.py
+++ b/net/tools/testserver/testserver.py
@@ -343,7 +343,6 @@
       self.GetClientCert,
       self.ClientCipherListHandler,
       self.CloseSocketHandler,
-      self.RangeResetHandler,
       self.DefaultResponseHandler]
     post_handlers = [
       self.EchoTitleHandler,
@@ -1560,153 +1559,6 @@
     self.wfile.close()
     return True
 
-  def RangeResetHandler(self):
-    """Send data broken up by connection resets every N (default 4K) bytes.
-    Support range requests.  If the data requested doesn't straddle a reset
-    boundary, it will all be sent.  Used for testing resuming downloads."""
-
-    def DataForRange(start, end):
-      """Data to be provided for a particular range of bytes."""
-      # Offset and scale to avoid too obvious (and hence potentially
-      # collidable) data.
-      return ''.join([chr(y % 256)
-                      for y in range(start * 2 + 15, end * 2 + 15, 2)])
-
-    if not self._ShouldHandleRequest('/rangereset'):
-      return False
-
-    # HTTP/1.1 is required for ETag and range support.
-    self.protocol_version = 'HTTP/1.1'
-    _, _, url_path, _, query, _ = urlparse.urlparse(self.path)
-
-    # Defaults
-    size = 8000
-    # Note that the rst is sent just before sending the rst_boundary byte.
-    rst_boundary = 4000
-    respond_to_range = True
-    hold_for_signal = False
-    rst_limit = -1
-    token = 'DEFAULT'
-    fail_precondition = 0
-    send_verifiers = True
-
-    # Parse the query
-    qdict = urlparse.parse_qs(query, True)
-    if 'size' in qdict:
-      size = int(qdict['size'][0])
-    if 'rst_boundary' in qdict:
-      rst_boundary = int(qdict['rst_boundary'][0])
-    if 'token' in qdict:
-      # Identifying token for stateful tests.
-      token = qdict['token'][0]
-    if 'rst_limit' in qdict:
-      # Max number of rsts for a given token.
-      rst_limit = int(qdict['rst_limit'][0])
-    if 'bounce_range' in qdict:
-      respond_to_range = False
-    if 'hold' in qdict:
-      # Note that hold_for_signal will not work with null range requests;
-      # see TODO below.
-      hold_for_signal = True
-    if 'no_verifiers' in qdict:
-      send_verifiers = False
-    if 'fail_precondition' in qdict:
-      fail_precondition = int(qdict['fail_precondition'][0])
-
-    # Record already set information, or set it.
-    rst_limit = TestPageHandler.rst_limits.setdefault(token, rst_limit)
-    if rst_limit != 0:
-      TestPageHandler.rst_limits[token] -= 1
-    fail_precondition = TestPageHandler.fail_precondition.setdefault(
-      token, fail_precondition)
-    if fail_precondition != 0:
-      TestPageHandler.fail_precondition[token] -= 1
-
-    first_byte = 0
-    last_byte = size - 1
-
-    # Does that define what we want to return, or do we need to apply
-    # a range?
-    range_response = False
-    range_header = self.headers.getheader('range')
-
-    if fail_precondition and self.headers.getheader('If-Range'):
-      # Failing a precondition for an If-Range just means that we are going to
-      # return the entire entity ignoring the Range header.
-      respond_to_range = False
-
-    if range_header and respond_to_range:
-      mo = re.match("bytes=(\d*)-(\d*)", range_header)
-      if mo.group(1):
-        first_byte = int(mo.group(1))
-      if mo.group(2):
-        last_byte = int(mo.group(2))
-      if last_byte > size - 1:
-        last_byte = size - 1
-      range_response = True
-      if last_byte < first_byte:
-        return False
-
-    if range_response:
-      self.send_response(206)
-      self.send_header('Content-Range',
-                       'bytes %d-%d/%d' % (first_byte, last_byte, size))
-    else:
-      self.send_response(200)
-    self.send_header('Content-Type', 'application/octet-stream')
-    self.send_header('Content-Length', last_byte - first_byte + 1)
-    if send_verifiers:
-      # If fail_precondition is non-zero, then the ETag for each request will be
-      # different.
-      etag = "%s%d" % (token, fail_precondition)
-      self.send_header('ETag', etag)
-      self.send_header('Last-Modified', 'Tue, 19 Feb 2013 14:32 EST')
-    self.end_headers()
-
-    if hold_for_signal:
-      # TODO(rdsmith/phajdan.jr): http://crbug.com/169519: Without writing
-      # a single byte, the self.server.handle_request() below hangs
-      # without processing new incoming requests.
-      self.wfile.write(DataForRange(first_byte, first_byte + 1))
-      first_byte = first_byte + 1
-      # handle requests until one of them clears this flag.
-      self.server.wait_for_download = True
-      while self.server.wait_for_download:
-        self.server.handle_request()
-
-    possible_rst = ((first_byte / rst_boundary) + 1) * rst_boundary
-    if possible_rst >= last_byte or rst_limit == 0:
-      # No RST has been requested in this range, so we don't need to
-      # do anything fancy; just write the data and let the python
-      # infrastructure close the connection.
-      self.wfile.write(DataForRange(first_byte, last_byte + 1))
-      self.wfile.flush()
-      return True
-
-    # We're resetting the connection part way in; go to the RST
-    # boundary and then send an RST.
-    # Because socket semantics do not guarantee that all the data will be
-    # sent when using the linger semantics to hard close a socket,
-    # we send the data and then wait for our peer to release us
-    # before sending the reset.
-    data = DataForRange(first_byte, possible_rst)
-    self.wfile.write(data)
-    self.wfile.flush()
-    self.server.wait_for_download = True
-    while self.server.wait_for_download:
-      self.server.handle_request()
-    l_onoff = 1  # Linger is active.
-    l_linger = 0  # Seconds to linger for.
-    self.connection.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER,
-                 struct.pack('ii', l_onoff, l_linger))
-
-    # Close all duplicates of the underlying socket to force the RST.
-    self.wfile.close()
-    self.rfile.close()
-    self.connection.close()
-
-    return True
-
   def DefaultResponseHandler(self):
     """This is the catch-all response handler for requests that aren't handled
     by one of the special handlers above.
diff --git a/net/url_request/url_request_job.cc b/net/url_request/url_request_job.cc
index 1b5c8f2a..140ab80 100644
--- a/net/url_request/url_request_job.cc
+++ b/net/url_request/url_request_job.cc
@@ -436,21 +436,22 @@
     bool defer_redirect = false;
     request_->NotifyReceivedRedirect(redirect_info, &defer_redirect);
 
-    // Ensure that the request wasn't detached or destroyed in
-    // NotifyReceivedRedirect
-    if (!request_ || !request_->has_delegate())
-      return;
-
-    // If we were not cancelled, then maybe follow the redirect.
-    if (request_->status().is_success()) {
-      if (defer_redirect) {
-        deferred_redirect_info_ = redirect_info;
-      } else {
-        FollowRedirect(redirect_info);
-      }
+    // Ensure that the request wasn't detached, destroyed, or canceled in
+    // NotifyReceivedRedirect.
+    if (!request_ || !request_->has_delegate() ||
+        !request_->status().is_success()) {
       return;
     }
-  } else if (NeedsAuth()) {
+
+    if (defer_redirect) {
+      deferred_redirect_info_ = redirect_info;
+    } else {
+      FollowRedirect(redirect_info);
+    }
+    return;
+  }
+
+  if (NeedsAuth()) {
     scoped_refptr<AuthChallengeInfo> auth_info;
     GetAuthChallengeInfo(&auth_info);
 
diff --git a/net/url_request/url_request_test_util.cc b/net/url_request/url_request_test_util.cc
index f98894a..31450c1 100644
--- a/net/url_request/url_request_test_util.cc
+++ b/net/url_request/url_request_test_util.cc
@@ -276,6 +276,11 @@
   // It doesn't make sense for the request to have IO pending at this point.
   DCHECK(!request->status().is_io_pending());
 
+  // If the request was cancelled in a redirect, it should not signal
+  // OnReadCompleted. Note that |cancel_in_rs_| may be true due to
+  // https://crbug.com/564848.
+  EXPECT_FALSE(cancel_in_rr_);
+
   if (response_started_count_ == 0)
     received_data_before_response_ = true;
 
diff --git a/ppapi/native_client/src/untrusted/pnacl_support_extension/BUILD.gn b/ppapi/native_client/src/untrusted/pnacl_support_extension/BUILD.gn
index 34f826c..dfe412e 100644
--- a/ppapi/native_client/src/untrusted/pnacl_support_extension/BUILD.gn
+++ b/ppapi/native_client/src/untrusted/pnacl_support_extension/BUILD.gn
@@ -31,14 +31,7 @@
     deps = [
       shim_target_tc_label,
     ]
-    shim_lib_path =
-        rebase_path(get_label_info(shim_target_tc_label, "target_out_dir") +
-                        "/$src_shim_name",
-                    root_build_dir)
-    shim_override_args = [
-      "--lib_override",
-      "$target_cpu,$shim_lib_path,$desired_shim_name",
-    ]
+    shim_cpu = target_cpu
 
     output_prefix = "$root_out_dir/pnacl/pnacl_public_"
     outputs = [
@@ -55,51 +48,43 @@
       "libpnacl_irt_shim_a",
       "pnacl_llc_nexe",
     ]
-    if (target_cpu == "arm") {
-      foreach(output_elem, outputs_from_toolchain) {
-        outputs += [ output_prefix + "arm_" + output_elem ]
-      }
-    } else if (target_cpu == "mipsel") {
-      foreach(output_elem, outputs_from_toolchain) {
-        outputs += [ output_prefix + "mips32_" + output_elem ]
-      }
-    } else if (target_cpu == "x86") {
-      foreach(output_elem, outputs_from_toolchain) {
-        outputs += [ output_prefix + "x86_32_" + output_elem ]
-      }
 
+    if (target_cpu == "arm") {
+      output_cpu = "arm"
+    } else if (target_cpu == "mipsel") {
+      output_cpu = "mips32"
+    } else if (target_cpu == "x64") {
+      output_cpu = "x86_64"
+    } else if (target_cpu == "x86") {
+      output_cpu = "x86_32"
+    } else {
+      assert(false, "unhandled target_cpu")
+    }
+
+    foreach(output_elem, outputs_from_toolchain) {
+      outputs += [ output_prefix + output_cpu + "_" + output_elem ]
+    }
+
+    if (is_win && target_cpu == "x86") {
       # On Windows, for offline testing (i.e., without component updater
       # selecting the platform-specific files with multi-CRXes), we need
       # to stage both x86-32 and x86-64 (because 32-bit chrome on 64-bit
       # windows will need 64-bit nexes).
-      if (is_win) {
-        foreach(output_elem, outputs_from_toolchain) {
-          outputs += [ output_prefix + "x86_64_" + output_elem ]
-        }
-        shim_target_tc_x64_label =
-            "$shim_target_label(${shim_toolchain_base}x64)"
-        deps += [ shim_target_tc_x64_label ]
-        shim_lib_x64_path =
-            rebase_path(get_label_info(shim_target_tc_x64_label,
-                                       "target_out_dir") + "/$src_shim_name",
-                        root_build_dir)
-        shim_override_args = [
-          "--lib_override",
-          "x64,$shim_lib_x64_path,$desired_shim_name",
-        ]
-      }
-    } else if (target_cpu == "x64") {
+
+      shim_target_tc_label = "$shim_target_label(${shim_toolchain_base}x64)"
+      deps += [ shim_target_tc_label ]
+
+      shim_cpu = "x64"
+
       foreach(output_elem, outputs_from_toolchain) {
         outputs += [ output_prefix + "x86_64_" + output_elem ]
       }
-    } else {
-      assert(false, "unhandled target_cpu")
     }
-    args = [
-      "--dest",
-      rebase_path("$root_out_dir/pnacl", root_build_dir),
-    ]
-    args += shim_override_args
+
+    shim_lib_path =
+        rebase_path(get_label_info(shim_target_tc_label, "target_out_dir") +
+                        "/$src_shim_name",
+                    root_build_dir)
 
     if (current_os == "chromeos") {
       toolchain_os = "linux"
@@ -107,19 +92,29 @@
       toolchain_os = current_os
     }
 
-    args += [
+    args = [
+      "--dest",
+      rebase_path("$root_out_dir/pnacl", root_build_dir),
+
+      "--lib_override",
+      "$shim_cpu,$shim_lib_path,$desired_shim_name",
+
       "--target_arch",
       target_cpu,
+
       "--info_template_path",
       rebase_path("//native_client/pnacl/driver/pnacl_info_template.json",
                   root_build_dir),
+
       "--pnacl_translator_path",
       rebase_path(
           "//native_client/toolchain/${toolchain_os}_x86/pnacl_translator",
           root_build_dir),
+
       "--package_version_path",
       rebase_path("//native_client/build/package_version/package_version.py",
                   root_build_dir),
+
       "--pnacl_package_name",
       "pnacl_translator",
 
diff --git a/printing/emf_win.cc b/printing/emf_win.cc
index d5e1888..8ee1d84 100644
--- a/printing/emf_win.cc
+++ b/printing/emf_win.cc
@@ -11,7 +11,7 @@
 #include "base/win/scoped_gdi_object.h"
 #include "base/win/scoped_hdc.h"
 #include "base/win/scoped_select_object.h"
-#include "skia/ext/platform_device.h"
+#include "skia/ext/skia_utils_win.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/gfx/codec/jpeg_codec.h"
 #include "ui/gfx/codec/png_codec.h"
diff --git a/printing/image_win.cc b/printing/image_win.cc
index 1411e16..398fb22 100644
--- a/printing/image_win.cc
+++ b/printing/image_win.cc
@@ -8,7 +8,7 @@
 #include "base/win/scoped_hdc.h"
 #include "base/win/scoped_select_object.h"
 #include "printing/metafile.h"
-#include "skia/ext/platform_device.h"
+#include "skia/ext/skia_utils_win.h"
 #include "ui/gfx/gdi_util.h"  // EMF support
 #include "ui/gfx/geometry/rect.h"
 
diff --git a/printing/printed_document_win.cc b/printing/printed_document_win.cc
index ddba4ca..e980039f 100644
--- a/printing/printed_document_win.cc
+++ b/printing/printed_document_win.cc
@@ -9,7 +9,7 @@
 #include "printing/printed_pages_source.h"
 #include "printing/printed_page.h"
 #include "printing/units.h"
-#include "skia/ext/platform_device.h"
+#include "skia/ext/skia_utils_win.h"
 
 namespace {
 
diff --git a/printing/printing_context_system_dialog_win.cc b/printing/printing_context_system_dialog_win.cc
index aaa5b68..d2e2b05 100644
--- a/printing/printing_context_system_dialog_win.cc
+++ b/printing/printing_context_system_dialog_win.cc
@@ -8,7 +8,7 @@
 #include "base/message_loop/message_loop.h"
 #include "printing/backend/win_helper.h"
 #include "printing/print_settings_initializer_win.h"
-#include "skia/ext/platform_device.h"
+#include "skia/ext/skia_utils_win.h"
 
 namespace printing {
 
diff --git a/printing/printing_context_win.cc b/printing/printing_context_win.cc
index e46e861a..4eff7228 100644
--- a/printing/printing_context_win.cc
+++ b/printing/printing_context_win.cc
@@ -16,7 +16,7 @@
 #include "printing/printing_context_system_dialog_win.h"
 #include "printing/printing_utils.h"
 #include "printing/units.h"
-#include "skia/ext/platform_device.h"
+#include "skia/ext/skia_utils_win.h"
 #include "ui/aura/remote_window_tree_host_win.h"
 #include "ui/aura/window.h"
 
diff --git a/remoting/remoting_android.gypi b/remoting/remoting_android.gypi
index 59c12a4..738e40e 100644
--- a/remoting/remoting_android.gypi
+++ b/remoting/remoting_android.gypi
@@ -173,8 +173,6 @@
           ],
           'variables': {
             'apk_name': 'Chromoting',
-            'android_app_version_name': '<(version_full)',
-            'android_app_version_code': '<!(python tools/android_version.py <(android_app_version_name))',
             'android_manifest_path': '<(SHARED_INTERMEDIATE_DIR)/remoting/android/AndroidManifest.xml',
             'java_in_dir': '<(remoting_apk_java_in_dir)',
             'native_lib_target': 'libremoting_client_jni',
diff --git a/remoting/tools/android_version.py b/remoting/tools/android_version.py
deleted file mode 100755
index da28bb1..0000000
--- a/remoting/tools/android_version.py
+++ /dev/null
@@ -1,28 +0,0 @@
-#!/usr/bin/env python
-# Copyright 2014 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Converts a dotted-quad version string to a single numeric value suitable for
-an Android package's internal version number."""
-
-import sys
-
-def main():
-  if len(sys.argv) != 2:
-    print "Usage: %s version-string" % sys.argv[0]
-    exit(1)
-
-  version_string = sys.argv[1]
-  version_components = version_string.split('.')
-  if len(version_components) != 4:
-    print "Expected 4 components."
-    exit(1)
-
-  branch = int(version_components[2])
-  patch = int(version_components[3])
-  print branch * 1000 + patch
-
-
-if __name__ == '__main__':
-  main()
diff --git a/sandbox/win/BUILD.gn b/sandbox/win/BUILD.gn
index 129f065a..22508699 100644
--- a/sandbox/win/BUILD.gn
+++ b/sandbox/win/BUILD.gn
@@ -196,6 +196,7 @@
     "src/handle_policy_test.cc",
     "src/integrity_level_test.cc",
     "src/ipc_ping_test.cc",
+    "src/lpc_policy_test.cc",
     "src/named_pipe_policy_test.cc",
     "src/policy_target_test.cc",
     "src/process_mitigations_test.cc",
diff --git a/sandbox/win/sandbox_win.gypi b/sandbox/win/sandbox_win.gypi
index 08d512a..ae8b51c3 100644
--- a/sandbox/win/sandbox_win.gypi
+++ b/sandbox/win/sandbox_win.gypi
@@ -219,6 +219,7 @@
         'src/handle_closer_test.cc',
         'src/integrity_level_test.cc',
         'src/ipc_ping_test.cc',
+        'src/lpc_policy_test.cc',
         'src/named_pipe_policy_test.cc',
         'src/policy_target_test.cc',
         'src/process_mitigations_test.cc',
diff --git a/sandbox/win/src/crosscall_client.h b/sandbox/win/src/crosscall_client.h
index 5b1bce7..777bab74 100644
--- a/sandbox/win/src/crosscall_client.h
+++ b/sandbox/win/src/crosscall_client.h
@@ -20,7 +20,7 @@
 //
 // The general interface of CrossCall is:
 //  ResultCode CrossCall(IPCProvider& ipc_provider,
-//                       uint32 tag,
+//                       uint32_t tag,
 //                       const Par1& p1, const Par2& p2,...pn
 //                       CrossCallReturn* answer)
 //
@@ -40,7 +40,7 @@
 
 // this is the assumed channel size. This can be overridden in a given
 // IPC implementation.
-const uint32 kIPCChannelSize = 1024;
+const uint32_t kIPCChannelSize = 1024;
 
 // The copy helper uses templates to deduce the appropriate copy function to
 // copy the input parameters in the buffer that is going to be send across the
@@ -67,9 +67,7 @@
   }
 
   // Returns the size of the input in bytes.
-  uint32 GetSize() const {
-    return sizeof(T);
-  }
+  uint32_t GetSize() const { return sizeof(T); }
 
   // Returns true if the current type is used as an In or InOut parameter.
   bool IsInOut() {
@@ -78,7 +76,7 @@
 
   // Returns this object's type.
   ArgType GetType() {
-    static_assert(sizeof(T) == sizeof(uint32), "specialization needed");
+    static_assert(sizeof(T) == sizeof(uint32_t), "specialization needed");
     return UINT32_TYPE;
   }
 
@@ -106,9 +104,7 @@
   }
 
   // Returns the size of the input in bytes.
-  uint32 GetSize() const {
-    return sizeof(t_);
-  }
+  uint32_t GetSize() const { return sizeof(t_); }
 
   // Returns true if the current type is used as an In or InOut parameter.
   bool IsInOut() {
@@ -147,12 +143,13 @@
 
   // Returns the size of the string in bytes. We define a NULL string to
   // be of zero length.
-  uint32 GetSize() const {
+  uint32_t GetSize() const {
     __try {
-      return (!t_) ? 0 : static_cast<uint32>(StringLength(t_) * sizeof(t_[0]));
+      return (!t_) ? 0
+                   : static_cast<uint32_t>(StringLength(t_) * sizeof(t_[0]));
     }
     __except(EXCEPTION_EXECUTE_HANDLER) {
-      return kuint32max;
+      return UINT32_MAX;
     }
   }
 
@@ -194,9 +191,7 @@
     return Base::Update(buffer);
   }
 
-  uint32 GetSize() const {
-    return Base::GetSize();
-  }
+  uint32_t GetSize() const { return Base::GetSize(); }
 
   bool IsInOut() {
     return Base::IsInOut();
@@ -224,9 +219,7 @@
     return Base::Update(buffer);
   }
 
-  uint32 GetSize() const {
-    return Base::GetSize();
-  }
+  uint32_t GetSize() const { return Base::GetSize(); }
 
   bool IsInOut() {
     return Base::IsInOut();
@@ -242,7 +235,8 @@
 // parameters.
 class InOutCountedBuffer : public CountedBuffer {
  public:
-  InOutCountedBuffer(void* buffer, uint32 size) : CountedBuffer(buffer, size) {}
+  InOutCountedBuffer(void* buffer, uint32_t size)
+      : CountedBuffer(buffer, size) {}
 };
 
 // This copy helper template specialization catches the cases where the
@@ -272,9 +266,7 @@
 
   // Returns the size of the string in bytes. We define a NULL string to
   // be of zero length.
-  uint32 GetSize() const {
-    return t_.Size();
-  }
+  uint32_t GetSize() const { return t_.Size(); }
 
   // Returns true if the current type is used as an In or InOut parameter.
   bool IsInOut() {
@@ -317,7 +309,9 @@
 
 // CrossCall template with one input parameter
 template <typename IPCProvider, typename Par1>
-ResultCode CrossCall(IPCProvider& ipc_provider, uint32 tag, const Par1& p1,
+ResultCode CrossCall(IPCProvider& ipc_provider,
+                     uint32_t tag,
+                     const Par1& p1,
                      CrossCallReturn* answer) {
   XCALL_GEN_PARAMS_OBJ(1, call_params);
   XCALL_GEN_COPY_PARAM(1, call_params);
@@ -334,8 +328,11 @@
 
 // CrossCall template with two input parameters.
 template <typename IPCProvider, typename Par1, typename Par2>
-ResultCode CrossCall(IPCProvider& ipc_provider, uint32 tag, const Par1& p1,
-                     const Par2& p2, CrossCallReturn* answer) {
+ResultCode CrossCall(IPCProvider& ipc_provider,
+                     uint32_t tag,
+                     const Par1& p1,
+                     const Par2& p2,
+                     CrossCallReturn* answer) {
   XCALL_GEN_PARAMS_OBJ(2, call_params);
   XCALL_GEN_COPY_PARAM(1, call_params);
   XCALL_GEN_COPY_PARAM(2, call_params);
@@ -352,8 +349,12 @@
 
 // CrossCall template with three input parameters.
 template <typename IPCProvider, typename Par1, typename Par2, typename Par3>
-ResultCode CrossCall(IPCProvider& ipc_provider, uint32 tag, const Par1& p1,
-                     const Par2& p2, const Par3& p3, CrossCallReturn* answer) {
+ResultCode CrossCall(IPCProvider& ipc_provider,
+                     uint32_t tag,
+                     const Par1& p1,
+                     const Par2& p2,
+                     const Par3& p3,
+                     CrossCallReturn* answer) {
   XCALL_GEN_PARAMS_OBJ(3, call_params);
   XCALL_GEN_COPY_PARAM(1, call_params);
   XCALL_GEN_COPY_PARAM(2, call_params);
@@ -371,10 +372,17 @@
 }
 
 // CrossCall template with four input parameters.
-template <typename IPCProvider, typename Par1, typename Par2, typename Par3,
+template <typename IPCProvider,
+          typename Par1,
+          typename Par2,
+          typename Par3,
           typename Par4>
-ResultCode CrossCall(IPCProvider& ipc_provider, uint32 tag, const Par1& p1,
-                     const Par2& p2, const Par3& p3, const Par4& p4,
+ResultCode CrossCall(IPCProvider& ipc_provider,
+                     uint32_t tag,
+                     const Par1& p1,
+                     const Par2& p2,
+                     const Par3& p3,
+                     const Par4& p4,
                      CrossCallReturn* answer) {
   XCALL_GEN_PARAMS_OBJ(4, call_params);
   XCALL_GEN_COPY_PARAM(1, call_params);
@@ -395,11 +403,20 @@
 }
 
 // CrossCall template with five input parameters.
-template <typename IPCProvider, typename Par1, typename Par2, typename Par3,
-          typename Par4, typename Par5>
-ResultCode CrossCall(IPCProvider& ipc_provider, uint32 tag, const Par1& p1,
-                     const Par2& p2, const Par3& p3, const Par4& p4,
-                     const Par5& p5, CrossCallReturn* answer) {
+template <typename IPCProvider,
+          typename Par1,
+          typename Par2,
+          typename Par3,
+          typename Par4,
+          typename Par5>
+ResultCode CrossCall(IPCProvider& ipc_provider,
+                     uint32_t tag,
+                     const Par1& p1,
+                     const Par2& p2,
+                     const Par3& p3,
+                     const Par4& p4,
+                     const Par5& p5,
+                     CrossCallReturn* answer) {
   XCALL_GEN_PARAMS_OBJ(5, call_params);
   XCALL_GEN_COPY_PARAM(1, call_params);
   XCALL_GEN_COPY_PARAM(2, call_params);
@@ -421,11 +438,22 @@
 }
 
 // CrossCall template with six input parameters.
-template <typename IPCProvider, typename Par1, typename Par2, typename Par3,
-          typename Par4, typename Par5, typename Par6>
-ResultCode CrossCall(IPCProvider& ipc_provider, uint32 tag, const Par1& p1,
-                     const Par2& p2, const Par3& p3, const Par4& p4,
-                     const Par5& p5, const Par6& p6, CrossCallReturn* answer) {
+template <typename IPCProvider,
+          typename Par1,
+          typename Par2,
+          typename Par3,
+          typename Par4,
+          typename Par5,
+          typename Par6>
+ResultCode CrossCall(IPCProvider& ipc_provider,
+                     uint32_t tag,
+                     const Par1& p1,
+                     const Par2& p2,
+                     const Par3& p3,
+                     const Par4& p4,
+                     const Par5& p5,
+                     const Par6& p6,
+                     CrossCallReturn* answer) {
   XCALL_GEN_PARAMS_OBJ(6, call_params);
   XCALL_GEN_COPY_PARAM(1, call_params);
   XCALL_GEN_COPY_PARAM(2, call_params);
@@ -449,11 +477,23 @@
 }
 
 // CrossCall template with seven input parameters.
-template <typename IPCProvider, typename Par1, typename Par2, typename Par3,
-          typename Par4, typename Par5, typename Par6, typename Par7>
-ResultCode CrossCall(IPCProvider& ipc_provider, uint32 tag, const Par1& p1,
-                     const Par2& p2, const Par3& p3, const Par4& p4,
-                     const Par5& p5, const Par6& p6, const Par7& p7,
+template <typename IPCProvider,
+          typename Par1,
+          typename Par2,
+          typename Par3,
+          typename Par4,
+          typename Par5,
+          typename Par6,
+          typename Par7>
+ResultCode CrossCall(IPCProvider& ipc_provider,
+                     uint32_t tag,
+                     const Par1& p1,
+                     const Par2& p2,
+                     const Par3& p3,
+                     const Par4& p4,
+                     const Par5& p5,
+                     const Par6& p6,
+                     const Par7& p7,
                      CrossCallReturn* answer) {
   XCALL_GEN_PARAMS_OBJ(7, call_params);
   XCALL_GEN_COPY_PARAM(1, call_params);
diff --git a/sandbox/win/src/crosscall_params.h b/sandbox/win/src/crosscall_params.h
index 7adb918..a601fc7 100644
--- a/sandbox/win/src/crosscall_params.h
+++ b/sandbox/win/src/crosscall_params.h
@@ -7,6 +7,7 @@
 
 #include <windows.h>
 #include <lmaccess.h>
+#include <stdint.h>
 
 #include <memory>
 
@@ -14,10 +15,10 @@
 #include "sandbox/win/src/internal_types.h"
 #include "sandbox/win/src/sandbox_types.h"
 
-// Increases |value| until there is no need for padding given an int64
+// Increases |value| until there is no need for padding given an int64_t
 // alignment. Returns the increased value.
-inline uint32 Align(uint32 value) {
-  uint32 alignment = sizeof(int64);
+inline uint32_t Align(uint32_t value) {
+  uint32_t alignment = sizeof(int64_t);
   return ((value + alignment - 1) / alignment) * alignment;
 }
 
@@ -27,7 +28,7 @@
 // parameters of an IPC call and CrossCallReturn models the output params and
 // the return value.
 //
-// An IPC call is defined by its 'tag' which is a (uint32) unique identifier
+// An IPC call is defined by its 'tag' which is a (uint32_t) unique identifier
 // that is used to route the IPC call to the proper server. Every tag implies
 // a complete call signature including the order and type of each parameter.
 //
@@ -36,7 +37,7 @@
 // them are not supported.
 //
 // Another limitation of CrossCall is that the return value and output
-// parameters can only be uint32 integers. Returning complex structures or
+// parameters can only be uint32_t integers. Returning complex structures or
 // strings is not supported.
 
 namespace sandbox {
@@ -47,7 +48,7 @@
 // Union of multiple types to be used as extended results
 // in the CrossCallReturn.
 union MultiType {
-  uint32 unsigned_int;
+  uint32_t unsigned_int;
   void* pointer;
   HANDLE handle;
   ULONG_PTR ulong_ptr;
@@ -63,8 +64,8 @@
 // Contains the information about a parameter in the ipc buffer.
 struct ParamInfo {
   ArgType type_;
-  uint32 offset_;
-  uint32 size_;
+  uint32_t offset_;
+  uint32_t size_;
 };
 
 // Models the return value and the return parameters of an IPC call
@@ -73,7 +74,7 @@
 // might have to use other integer types.
 struct CrossCallReturn {
   // the IPC tag. It should match the original IPC tag.
-  uint32 tag;
+  uint32_t tag;
   // The result of the IPC operation itself.
   ResultCode call_outcome;
   // the result of the IPC call as executed in the server. The interpretation
@@ -83,7 +84,7 @@
     DWORD    win32_result;
   };
   // Number of extended return values.
-  uint32 extended_count;
+  uint32_t extended_count;
   // for calls that should return a windows handle. It is found here.
   HANDLE handle;
   // The array of extended values.
@@ -104,9 +105,7 @@
 class CrossCallParams {
  public:
   // Returns the tag (ipc unique id) associated with this IPC.
-  uint32 GetTag() const {
-    return tag_;
-  }
+  uint32_t GetTag() const { return tag_; }
 
   // Returns the beggining of the buffer where the IPC params can be stored.
   // prior to an IPC call
@@ -115,9 +114,7 @@
   }
 
   // Returns how many parameter this IPC call should have.
-  const uint32 GetParamsCount() const {
-    return params_count_;
-  }
+  const uint32_t GetParamsCount() const { return params_count_; }
 
   // Returns a pointer to the CrossCallReturn structure.
   CrossCallReturn* GetCallReturn() {
@@ -139,14 +136,14 @@
 
  protected:
   // constructs the IPC call params. Called only from the derived classes
-  CrossCallParams(uint32 tag, uint32 params_count)
+  CrossCallParams(uint32_t tag, uint32_t params_count)
       : tag_(tag), is_in_out_(0), params_count_(params_count) {}
 
  private:
-  uint32 tag_;
-  uint32 is_in_out_;
+  uint32_t tag_;
+  uint32_t is_in_out_;
   CrossCallReturn call_return;
-  const uint32 params_count_;
+  const uint32_t params_count_;
   DISALLOW_COPY_AND_ASSIGN(CrossCallParams);
 };
 
@@ -192,37 +189,40 @@
 class ActualCallParams : public CrossCallParams {
  public:
   // constructor. Pass the ipc unique tag as input
-  explicit ActualCallParams(uint32 tag)
+  explicit ActualCallParams(uint32_t tag)
       : CrossCallParams(tag, NUMBER_PARAMS) {
     param_info_[0].offset_ =
-        static_cast<uint32>(parameters_ - reinterpret_cast<char*>(this));
+        static_cast<uint32_t>(parameters_ - reinterpret_cast<char*>(this));
   }
 
   // Testing-only constructor. Allows setting the |number_params| to a
   // wrong value.
-  ActualCallParams(uint32 tag, uint32 number_params)
+  ActualCallParams(uint32_t tag, uint32_t number_params)
       : CrossCallParams(tag, number_params) {
     param_info_[0].offset_ =
-        static_cast<uint32>(parameters_ - reinterpret_cast<char*>(this));
+        static_cast<uint32_t>(parameters_ - reinterpret_cast<char*>(this));
   }
 
   // Testing-only method. Allows setting the apparent size to a wrong value.
   // returns the previous size.
-  uint32 OverrideSize(uint32 new_size) {
-    uint32 previous_size = param_info_[NUMBER_PARAMS].offset_;
+  uint32_t OverrideSize(uint32_t new_size) {
+    uint32_t previous_size = param_info_[NUMBER_PARAMS].offset_;
     param_info_[NUMBER_PARAMS].offset_ = new_size;
     return previous_size;
   }
 
   // Copies each paramter into the internal buffer. For each you must supply:
   // index: 0 for the first param, 1 for the next an so on
-  bool CopyParamIn(uint32 index, const void* parameter_address, uint32 size,
-                   bool is_in_out, ArgType type) {
+  bool CopyParamIn(uint32_t index,
+                   const void* parameter_address,
+                   uint32_t size,
+                   bool is_in_out,
+                   ArgType type) {
     if (index >= NUMBER_PARAMS) {
       return false;
     }
 
-    if (kuint32max == size) {
+    if (UINT32_MAX == size) {
       // Memory error while getting the size.
       return false;
     }
@@ -267,9 +267,7 @@
 
   // Returns the total size of the buffer. Only valid once all the paramters
   // have been copied in with CopyParamIn.
-  uint32 GetSize() const {
-    return param_info_[NUMBER_PARAMS].offset_;
-  }
+  uint32_t GetSize() const { return param_info_[NUMBER_PARAMS].offset_; }
 
  protected:
   ActualCallParams() : CrossCallParams(0, NUMBER_PARAMS) { }
diff --git a/sandbox/win/src/crosscall_server.cc b/sandbox/win/src/crosscall_server.cc
index 6f8bd74..f0e1183a 100644
--- a/sandbox/win/src/crosscall_server.cc
+++ b/sandbox/win/src/crosscall_server.cc
@@ -26,7 +26,7 @@
 
 // Returns the actual size for the parameters in an IPC buffer. Returns
 // zero if the |param_count| is zero or too big.
-uint32 GetActualBufferSize(uint32 param_count, void* buffer_base) {
+uint32_t GetActualBufferSize(uint32_t param_count, void* buffer_base) {
   // The template types are used to calculate the maximum expected size.
   typedef ActualCallParams<1, kMaxBufferSize> ActualCP1;
   typedef ActualCallParams<2, kMaxBufferSize> ActualCP2;
@@ -66,8 +66,9 @@
 }
 
 // Verifies that the declared sizes of an IPC buffer are within range.
-bool IsSizeWithinRange(uint32 buffer_size, uint32 min_declared_size,
-                       uint32 declared_size) {
+bool IsSizeWithinRange(uint32_t buffer_size,
+                       uint32_t min_declared_size,
+                       uint32_t declared_size) {
   if ((buffer_size < min_declared_size) ||
       (sizeof(CrossCallParamsEx) > min_declared_size)) {
     // Minimal computed size bigger than existing buffer or param_count
@@ -104,8 +105,8 @@
 // have destructors or else you get Compiler Error C2712. So no DCHECKs
 // inside this function.
 CrossCallParamsEx* CrossCallParamsEx::CreateFromBuffer(void* buffer_base,
-                                                       uint32 buffer_size,
-                                                       uint32* output_size) {
+                                                       uint32_t buffer_size,
+                                                       uint32_t* output_size) {
   // IMPORTANT: Everything inside buffer_base and derived from it such
   // as param_count and declared_size is untrusted.
   if (NULL == buffer_base) {
@@ -119,9 +120,9 @@
   }
 
   char* backing_mem = NULL;
-  uint32 param_count = 0;
-  uint32 declared_size;
-  uint32 min_declared_size;
+  uint32_t param_count = 0;
+  uint32_t declared_size;
+  uint32_t min_declared_size;
   CrossCallParamsEx* copied_params = NULL;
 
   // Touching the untrusted buffer is done under a SEH try block. This
@@ -176,8 +177,8 @@
 
   // Verify here that all and each parameters make sense. This is done in the
   // local copy.
-  for (uint32 ix =0; ix != param_count; ++ix) {
-    uint32 size = 0;
+  for (uint32_t ix = 0; ix != param_count; ++ix) {
+    uint32_t size = 0;
     ArgType type;
     char* address = reinterpret_cast<char*>(
                         copied_params->GetRawParameter(ix, &size, &type));
@@ -198,7 +199,8 @@
 }
 
 // Accessors to the parameters in the raw buffer.
-void* CrossCallParamsEx::GetRawParameter(uint32 index, uint32* size,
+void* CrossCallParamsEx::GetRawParameter(uint32_t index,
+                                         uint32_t* size,
                                          ArgType* type) {
   if (index >= GetParamsCount()) {
     return NULL;
@@ -212,20 +214,20 @@
 }
 
 // Covers common case for 32 bit integers.
-bool CrossCallParamsEx::GetParameter32(uint32 index, uint32* param) {
-  uint32 size = 0;
+bool CrossCallParamsEx::GetParameter32(uint32_t index, uint32_t* param) {
+  uint32_t size = 0;
   ArgType type;
   void* start = GetRawParameter(index, &size, &type);
   if ((NULL == start) || (4 != size) || (UINT32_TYPE != type)) {
     return false;
   }
   // Copy the 4 bytes.
-  *(reinterpret_cast<uint32*>(param)) = *(reinterpret_cast<uint32*>(start));
+  *(reinterpret_cast<uint32_t*>(param)) = *(reinterpret_cast<uint32_t*>(start));
   return true;
 }
 
-bool CrossCallParamsEx::GetParameterVoidPtr(uint32 index, void** param) {
-  uint32 size = 0;
+bool CrossCallParamsEx::GetParameterVoidPtr(uint32_t index, void** param) {
+  uint32_t size = 0;
   ArgType type;
   void* start = GetRawParameter(index, &size, &type);
   if ((NULL == start) || (sizeof(void*) != size) || (VOIDPTR_TYPE != type)) {
@@ -237,8 +239,9 @@
 
 // Covers the common case of reading a string. Note that the string is not
 // scanned for invalid characters.
-bool CrossCallParamsEx::GetParameterStr(uint32 index, base::string16* string) {
-  uint32 size = 0;
+bool CrossCallParamsEx::GetParameterStr(uint32_t index,
+                                        base::string16* string) {
+  uint32_t size = 0;
   ArgType type;
   void* start = GetRawParameter(index, &size, &type);
   if (WCHAR_TYPE != type) {
@@ -258,9 +261,10 @@
   return true;
 }
 
-bool CrossCallParamsEx::GetParameterPtr(uint32 index, uint32 expected_size,
+bool CrossCallParamsEx::GetParameterPtr(uint32_t index,
+                                        uint32_t expected_size,
                                         void** pointer) {
-  uint32 size = 0;
+  uint32_t size = 0;
   ArgType type;
   void* start = GetRawParameter(index, &size, &type);
 
diff --git a/sandbox/win/src/crosscall_server.h b/sandbox/win/src/crosscall_server.h
index 824b63e..9779c11f 100644
--- a/sandbox/win/src/crosscall_server.h
+++ b/sandbox/win/src/crosscall_server.h
@@ -7,8 +7,9 @@
 
 #include <string>
 #include <vector>
-#include "base/basictypes.h"
+
 #include "base/callback.h"
+#include "base/macros.h"
 #include "base/strings/string16.h"
 #include "sandbox/win/src/crosscall_params.h"
 
@@ -94,31 +95,31 @@
   // 1) validate the IPC buffer. returns NULL is the IPCbuffer is malformed.
   // 2) make a copy of the IPCbuffer (parameter capture)
   static CrossCallParamsEx* CreateFromBuffer(void* buffer_base,
-                                             uint32 buffer_size,
-                                             uint32* output_size);
+                                             uint32_t buffer_size,
+                                             uint32_t* output_size);
 
   // Provides IPCinput parameter raw access:
   // index : the parameter to read; 0 is the first parameter
   // returns NULL if the parameter is non-existent. If it exists it also
   // returns the size in *size
-  void* GetRawParameter(uint32 index, uint32* size, ArgType* type);
+  void* GetRawParameter(uint32_t index, uint32_t* size, ArgType* type);
 
   // Gets a parameter that is four bytes in size.
   // Returns false if the parameter does not exist or is not 32 bits wide.
-  bool GetParameter32(uint32 index, uint32* param);
+  bool GetParameter32(uint32_t index, uint32_t* param);
 
   // Gets a parameter that is void pointer in size.
   // Returns false if the parameter does not exist or is not void pointer sized.
-  bool GetParameterVoidPtr(uint32 index, void** param);
+  bool GetParameterVoidPtr(uint32_t index, void** param);
 
   // Gets a parameter that is a string. Returns false if the parameter does not
   // exist.
-  bool GetParameterStr(uint32 index, base::string16* string);
+  bool GetParameterStr(uint32_t index, base::string16* string);
 
   // Gets a parameter that is an in/out buffer. Returns false is the parameter
   // does not exist or if the size of the actual parameter is not equal to the
   // expected size.
-  bool GetParameterPtr(uint32 index, uint32 expected_size, void** pointer);
+  bool GetParameterPtr(uint32_t index, uint32_t expected_size, void** pointer);
 
   // Frees the memory associated with the IPC parameters.
   static void operator delete(void* raw_memory) throw();
diff --git a/sandbox/win/src/ipc_unittest.cc b/sandbox/win/src/ipc_unittest.cc
index 0dc9571..e8b0b81 100644
--- a/sandbox/win/src/ipc_unittest.cc
+++ b/sandbox/win/src/ipc_unittest.cc
@@ -2,7 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "base/basictypes.h"
+#include <stdint.h>
+
 #include "sandbox/win/src/crosscall_client.h"
 #include "sandbox/win/src/crosscall_server.h"
 #include "sandbox/win/src/sharedmem_ipc_client.h"
@@ -158,7 +159,7 @@
   SharedMemIPCClient client(mem);
 
   CrossCallReturn answer;
-  uint32 tag1 = 666;
+  uint32_t tag1 = 666;
   const wchar_t *text = L"98765 - 43210";
   base::string16 copied_text;
   CrossCallParamsEx* actual_params;
@@ -171,13 +172,13 @@
   EXPECT_STREQ(text, copied_text.c_str());
 
   // Check with an empty string.
-  uint32 tag2 = 777;
+  uint32_t tag2 = 777;
   const wchar_t* null_text = NULL;
   CrossCall(client, tag2, null_text, &answer);
   actual_params = reinterpret_cast<CrossCallParamsEx*>(client.GetBuffer());
   EXPECT_EQ(1, actual_params->GetParamsCount());
   EXPECT_EQ(tag2, actual_params->GetTag());
-  uint32 param_size = 1;
+  uint32_t param_size = 1;
   ArgType type = INVALID_TYPE;
   void* param_addr = actual_params->GetRawParameter(0, &param_size, &type);
   EXPECT_TRUE(NULL != param_addr);
@@ -185,7 +186,7 @@
   EXPECT_EQ(WCHAR_TYPE, type);
   EXPECT_TRUE(actual_params->GetParameterStr(0, &copied_text));
 
-  uint32 tag3 = 888;
+  uint32_t tag3 = 888;
   param_size = 1;
   copied_text.clear();
 
@@ -233,8 +234,8 @@
   client_control->server_alive = HANDLE(1);
   FixChannels(client_control, base_start, kIPCChannelSize, FIX_PONG_READY);
 
-  uint32 tag1 = 999;
-  uint32 tag2 = 111;
+  uint32_t tag1 = 999;
+  uint32_t tag2 = 111;
   const wchar_t *text = L"godzilla";
   CrossCallParamsEx* actual_params;
 
@@ -248,7 +249,7 @@
   EXPECT_EQ(1, actual_params->GetParamsCount());
   EXPECT_EQ(tag2, actual_params->GetTag());
   ArgType type = INVALID_TYPE;
-  uint32 param_size = 1;
+  uint32_t param_size = 1;
   void* param_addr = actual_params->GetRawParameter(0, &param_size, &type);
   ASSERT_EQ(sizeof(dw), param_size);
   EXPECT_EQ(UINT32_TYPE, type);
@@ -299,13 +300,13 @@
 TEST(IPCTest, CrossCallValidation) {
   // First a sanity test with a well formed parameter object.
   unsigned long value = 124816;
-  const uint32 kTag = 33;
-  const uint32 kBufferSize = 256;
+  const uint32_t kTag = 33;
+  const uint32_t kBufferSize = 256;
   ActualCallParams<1, kBufferSize> params_1(kTag);
   params_1.CopyParamIn(0, &value, sizeof(value), false, UINT32_TYPE);
   void* buffer = const_cast<void*>(params_1.GetBuffer());
 
-  uint32 out_size = 0;
+  uint32_t out_size = 0;
   CrossCallParamsEx* ccp = 0;
   ccp = CrossCallParamsEx::CreateFromBuffer(buffer, params_1.GetSize(),
                                             &out_size);
@@ -318,9 +319,9 @@
   // Test that we handle integer overflow on the number of params
   // correctly. We use a test-only ctor for ActualCallParams that
   // allows to create malformed cross-call buffers.
-  const int32 kPtrDiffSz = sizeof(ptrdiff_t);
-  for (int32 ix = -1; ix != 3; ++ix) {
-    uint32 fake_num_params = (kuint32max / kPtrDiffSz) + ix;
+  const int32_t kPtrDiffSz = sizeof(ptrdiff_t);
+  for (int32_t ix = -1; ix != 3; ++ix) {
+    uint32_t fake_num_params = (UINT32_MAX / kPtrDiffSz) + ix;
     ActualCallParams<1, kBufferSize> params_2(kTag, fake_num_params);
     params_2.CopyParamIn(0, &value, sizeof(value), false, UINT32_TYPE);
     buffer = const_cast<void*>(params_2.GetBuffer());
@@ -337,7 +338,7 @@
   buffer = const_cast<void*>(params_3.GetBuffer());
   EXPECT_TRUE(NULL != buffer);
 
-  uint32 correct_size = params_3.OverrideSize(1);
+  uint32_t correct_size = params_3.OverrideSize(1);
   ccp = CrossCallParamsEx::CreateFromBuffer(buffer, kBufferSize, &out_size);
   EXPECT_TRUE(NULL == ccp);
 
@@ -389,9 +390,8 @@
 
 class CrossCallParamsMock : public CrossCallParams {
  public:
-  CrossCallParamsMock(uint32 tag, uint32 params_count)
-      :  CrossCallParams(tag, params_count) {
-  }
+  CrossCallParamsMock(uint32_t tag, uint32_t params_count)
+      : CrossCallParams(tag, params_count) {}
 };
 
 void FakeOkAnswerInChannel(void* channel) {
@@ -436,7 +436,7 @@
 
   EXPECT_EQ(0, client_control->channels[1].ipc_tag);
 
-  uint32 tag = 7654;
+  uint32_t tag = 7654;
   CrossCallReturn answer;
   CrossCallParamsMock* params1 = new(buff1) CrossCallParamsMock(tag, 1);
   FakeOkAnswerInChannel(buff1);
@@ -535,7 +535,7 @@
   ::Sleep(1);
 
   void* buff0 = client.GetBuffer();
-  uint32 tag = 4321;
+  uint32_t tag = 4321;
   CrossCallReturn answer;
   CrossCallParamsMock* params1 = new(buff0) CrossCallParamsMock(tag, 1);
   FakeOkAnswerInChannel(buff0);
@@ -570,15 +570,13 @@
   }
 
  private:
-  bool CallOneHandler(IPCInfo* ipc, HANDLE p1, uint32 p2) {
+  bool CallOneHandler(IPCInfo* ipc, HANDLE p1, uint32_t p2) {
     ipc->return_info.extended[0].handle = p1;
     ipc->return_info.extended[1].unsigned_int = p2;
     return true;
   }
 
-  bool CallTwoHandler(IPCInfo* ipc, HANDLE p1, uint32 p2) {
-    return true;
-  }
+  bool CallTwoHandler(IPCInfo* ipc, HANDLE p1, uint32_t p2) { return true; }
 };
 
 UnitTestIPCDispatcher::UnitTestIPCDispatcher() {
diff --git a/sandbox/win/src/lpc_policy_test.cc b/sandbox/win/src/lpc_policy_test.cc
new file mode 100644
index 0000000..ac7b39f3
--- /dev/null
+++ b/sandbox/win/src/lpc_policy_test.cc
@@ -0,0 +1,156 @@
+// 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.
+
+// These tests have been added to specifically tests issues arising from (A)LPC
+// lock down.
+
+#include <algorithm>
+#include <cctype>
+
+#include <windows.h>
+#include <winioctl.h>
+
+#include "base/win/windows_version.h"
+#include "sandbox/win/src/sandbox.h"
+#include "sandbox/win/src/sandbox_factory.h"
+#include "sandbox/win/src/sandbox_policy.h"
+#include "sandbox/win/tests/common/controller.h"
+#include "sandbox/win/tests/common/test_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace sandbox {
+
+// Converts LCID to std::wstring for passing to sbox tests.
+std::wstring LcidToWString(LCID lcid) {
+  wchar_t buff[10] = {0};
+  int res = swprintf_s(buff, sizeof(buff) / sizeof(buff[0]), L"%08x", lcid);
+  if (-1 != res) {
+    return std::wstring(buff);
+  }
+  return std::wstring();
+}
+
+// Converts LANGID to std::wstring for passing to sbox tests.
+std::wstring LangidToWString(LANGID langid) {
+  wchar_t buff[10] = {0};
+  int res = swprintf_s(buff, sizeof(buff) / sizeof(buff[0]), L"%04x", langid);
+  if (-1 != res) {
+    return std::wstring(buff);
+  }
+  return std::wstring();
+}
+
+SBOX_TESTS_COMMAND int Lpc_GetUserDefaultLangID(int argc, wchar_t** argv) {
+  if (argc != 1)
+    return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+  std::wstring expected_langid_string(argv[0]);
+
+  // This will cause an exception if not warmed up suitably.
+  LANGID langid = ::GetUserDefaultLangID();
+
+  std::wstring langid_string = LangidToWString(langid);
+  if (0 == wcsncmp(langid_string.c_str(), expected_langid_string.c_str(), 4)) {
+    return SBOX_TEST_SUCCEEDED;
+  }
+  return SBOX_TEST_FAILED;
+}
+
+TEST(LpcPolicyTest, GetUserDefaultLangID) {
+  LANGID langid = ::GetUserDefaultLangID();
+  std::wstring cmd = L"Lpc_GetUserDefaultLangID " + LangidToWString(langid);
+  TestRunner runner;
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(cmd.c_str()));
+}
+
+SBOX_TESTS_COMMAND int Lpc_GetUserDefaultLCID(int argc, wchar_t** argv) {
+  if (argc != 1)
+    return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+  std::wstring expected_lcid_string(argv[0]);
+
+  // This will cause an exception if not warmed up suitably.
+  LCID lcid = ::GetUserDefaultLCID();
+
+  std::wstring lcid_string = LcidToWString(lcid);
+  if (0 == wcsncmp(lcid_string.c_str(), expected_lcid_string.c_str(), 8)) {
+    return SBOX_TEST_SUCCEEDED;
+  }
+  return SBOX_TEST_FAILED;
+}
+
+TEST(LpcPolicyTest, GetUserDefaultLCID) {
+  LCID lcid = ::GetUserDefaultLCID();
+  std::wstring cmd = L"Lpc_GetUserDefaultLCID " + LcidToWString(lcid);
+  TestRunner runner;
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(cmd.c_str()));
+}
+
+// GetUserDefaultLocaleName is not available on WIN XP.  So we'll
+// load it on-the-fly.
+const wchar_t kKernel32DllName[] = L"kernel32.dll";
+typedef int(WINAPI* GetUserDefaultLocaleNameFunction)(LPWSTR lpLocaleName,
+                                                      int cchLocaleName);
+
+SBOX_TESTS_COMMAND int Lpc_GetUserDefaultLocaleName(int argc, wchar_t** argv) {
+  if (argc != 1)
+    return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+  std::wstring expected_locale_name(argv[0]);
+  static GetUserDefaultLocaleNameFunction GetUserDefaultLocaleName_func = NULL;
+  if (!GetUserDefaultLocaleName_func) {
+    // GetUserDefaultLocaleName is not available on WIN XP.  So we'll
+    // load it on-the-fly.
+    HMODULE kernel32_dll = ::GetModuleHandle(kKernel32DllName);
+    if (!kernel32_dll) {
+      return SBOX_TEST_FAILED;
+    }
+    GetUserDefaultLocaleName_func =
+        reinterpret_cast<GetUserDefaultLocaleNameFunction>(
+            GetProcAddress(kernel32_dll, "GetUserDefaultLocaleName"));
+    if (!GetUserDefaultLocaleName_func) {
+      return SBOX_TEST_FAILED;
+    }
+  }
+  wchar_t locale_name[LOCALE_NAME_MAX_LENGTH] = {0};
+  // This will cause an exception if not warmed up suitably.
+  int ret = GetUserDefaultLocaleName_func(
+      locale_name, LOCALE_NAME_MAX_LENGTH * sizeof(wchar_t));
+  if (!ret) {
+    return SBOX_TEST_FAILED;
+  }
+  if (!wcsnlen(locale_name, LOCALE_NAME_MAX_LENGTH)) {
+    return SBOX_TEST_FAILED;
+  }
+  if (0 == wcsncmp(locale_name, expected_locale_name.c_str(),
+                   LOCALE_NAME_MAX_LENGTH)) {
+    return SBOX_TEST_SUCCEEDED;
+  }
+  return SBOX_TEST_FAILED;
+}
+
+TEST(LpcPolicyTest, GetUserDefaultLocaleName) {
+  // GetUserDefaultLocaleName is not available before Vista.
+  if (base::win::GetVersion() < base::win::VERSION_VISTA) {
+    return;
+  }
+  static GetUserDefaultLocaleNameFunction GetUserDefaultLocaleName_func = NULL;
+  if (!GetUserDefaultLocaleName_func) {
+    // GetUserDefaultLocaleName is not available on WIN XP.  So we'll
+    // load it on-the-fly.
+    HMODULE kernel32_dll = ::GetModuleHandle(kKernel32DllName);
+    EXPECT_NE(NULL, int(kernel32_dll));
+    GetUserDefaultLocaleName_func =
+        reinterpret_cast<GetUserDefaultLocaleNameFunction>(
+            GetProcAddress(kernel32_dll, "GetUserDefaultLocaleName"));
+    EXPECT_NE(NULL, int(GetUserDefaultLocaleName_func));
+  }
+  wchar_t locale_name[LOCALE_NAME_MAX_LENGTH] = {0};
+  EXPECT_NE(0, GetUserDefaultLocaleName_func(
+                   locale_name, LOCALE_NAME_MAX_LENGTH * sizeof(wchar_t)));
+  EXPECT_NE(0U, wcsnlen(locale_name, LOCALE_NAME_MAX_LENGTH));
+  std::wstring cmd =
+      L"Lpc_GetUserDefaultLocaleName " + std::wstring(locale_name);
+  TestRunner runner;
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(cmd.c_str()));
+}
+
+}  // namespace sandbox
diff --git a/sandbox/win/src/sandbox_policy.h b/sandbox/win/src/sandbox_policy.h
index c1af857..0c3e847 100644
--- a/sandbox/win/src/sandbox_policy.h
+++ b/sandbox/win/src/sandbox_policy.h
@@ -80,7 +80,7 @@
   //   not compatible with AppContainer, see SetAppContainer.
   // lockdown: the security level for the token that comes into force after the
   //   process calls TargetServices::LowerToken() or the process calls
-  //   ReverToSelf(). See the explanation of each level in the TokenLevel
+  //   RevertToSelf(). See the explanation of each level in the TokenLevel
   //   definition.
   // Return value: SBOX_ALL_OK if the setting succeeds and false otherwise.
   //   Returns false if the lockdown value is more permissive than the initial
diff --git a/sandbox/win/src/sandbox_types.h b/sandbox/win/src/sandbox_types.h
index 3e531be4..b749b9c 100644
--- a/sandbox/win/src/sandbox_types.h
+++ b/sandbox/win/src/sandbox_types.h
@@ -54,13 +54,14 @@
 // If the sandbox cannot create a secure environment for the target, the
 // target will be forcibly terminated. These are the process exit codes.
 enum TerminationCodes {
-  SBOX_FATAL_INTEGRITY = 7006,       // Could not set the integrity level.
-  SBOX_FATAL_DROPTOKEN = 7007,       // Could not lower the token.
-  SBOX_FATAL_FLUSHANDLES = 7008,     // Failed to flush registry handles.
-  SBOX_FATAL_CACHEDISABLE = 7009,    // Failed to forbid HCKU caching.
-  SBOX_FATAL_CLOSEHANDLES = 7010,    // Failed to close pending handles.
-  SBOX_FATAL_MITIGATION = 7011,      // Could not set the mitigation policy.
-  SBOX_FATAL_MEMORY_EXCEEDED = 7012, // Exceeded the job memory limit.
+  SBOX_FATAL_INTEGRITY = 7006,        // Could not set the integrity level.
+  SBOX_FATAL_DROPTOKEN = 7007,        // Could not lower the token.
+  SBOX_FATAL_FLUSHANDLES = 7008,      // Failed to flush registry handles.
+  SBOX_FATAL_CACHEDISABLE = 7009,     // Failed to forbid HCKU caching.
+  SBOX_FATAL_CLOSEHANDLES = 7010,     // Failed to close pending handles.
+  SBOX_FATAL_MITIGATION = 7011,       // Could not set the mitigation policy.
+  SBOX_FATAL_MEMORY_EXCEEDED = 7012,  // Exceeded the job memory limit.
+  SBOX_FATAL_WARMUP = 7013,           // Failed to warmup.
   SBOX_FATAL_LAST
 };
 
diff --git a/sandbox/win/src/target_services.cc b/sandbox/win/src/target_services.cc
index 116f0c92..e10f7ca 100644
--- a/sandbox/win/src/target_services.cc
+++ b/sandbox/win/src/target_services.cc
@@ -59,6 +59,44 @@
   return true;
 }
 
+// GetUserDefaultLocaleName is not available on WIN XP.  So we'll
+// load it on-the-fly.
+const wchar_t kKernel32DllName[] = L"kernel32.dll";
+typedef decltype(GetUserDefaultLocaleName)* GetUserDefaultLocaleNameFunction;
+
+// Warm up language subsystems before the sandbox is turned on.
+// Tested on Win8.1 x64:
+// This needs to happen after RevertToSelf() is called, because (at least) in
+// the case of GetUserDefaultLCID() it checks the TEB to see if the process is
+// impersonating (TEB!IsImpersonating). If it is, the cached locale information
+// is not used, nor is it set. Therefore, calls after RevertToSelf() will not
+// have warmed-up values to use.
+bool WarmupWindowsLocales() {
+  // NOTE(liamjm): When last checked (Win 8.1 x64) it wasn't necessary to
+  // warmup all of these functions, but let's not assume that.
+  ::GetUserDefaultLangID();
+  ::GetUserDefaultLCID();
+  if (base::win::GetVersion() >= base::win::VERSION_VISTA) {
+    static GetUserDefaultLocaleNameFunction GetUserDefaultLocaleName_func =
+        NULL;
+    if (!GetUserDefaultLocaleName_func) {
+      HMODULE kernel32_dll = ::GetModuleHandle(kKernel32DllName);
+      if (!kernel32_dll) {
+        return false;
+      }
+      GetUserDefaultLocaleName_func =
+          reinterpret_cast<GetUserDefaultLocaleNameFunction>(
+              GetProcAddress(kernel32_dll, "GetUserDefaultLocaleName"));
+      if (!GetUserDefaultLocaleName_func) {
+        return false;
+      }
+    }
+    wchar_t localeName[LOCALE_NAME_MAX_LENGTH] = {0};
+    return (0 != GetUserDefaultLocaleName_func(
+                     localeName, LOCALE_NAME_MAX_LENGTH * sizeof(wchar_t)));
+  }
+  return true;
+}
 
 // Used as storage for g_target_services, because other allocation facilities
 // are not available early. We can't use a regular function static because on
@@ -97,6 +135,8 @@
     ::TerminateProcess(::GetCurrentProcess(), SBOX_FATAL_FLUSHANDLES);
   if (ERROR_SUCCESS != ::RegDisablePredefinedCache())
     ::TerminateProcess(::GetCurrentProcess(), SBOX_FATAL_CACHEDISABLE);
+  if (!WarmupWindowsLocales())
+    ::TerminateProcess(::GetCurrentProcess(), SBOX_FATAL_WARMUP);
   bool is_csrss_connected = true;
   if (!CloseOpenHandles(&is_csrss_connected))
     ::TerminateProcess(::GetCurrentProcess(), SBOX_FATAL_CLOSEHANDLES);
diff --git a/skia/ext/bitmap_platform_device_win.cc b/skia/ext/bitmap_platform_device_win.cc
index 9cd3d70..f600b96d 100644
--- a/skia/ext/bitmap_platform_device_win.cc
+++ b/skia/ext/bitmap_platform_device_win.cc
@@ -10,6 +10,7 @@
 #include "base/win/win_util.h"
 #include "skia/ext/bitmap_platform_device_win.h"
 #include "skia/ext/platform_canvas.h"
+#include "skia/ext/skia_utils_win.h"
 #include "third_party/skia/include/core/SkMatrix.h"
 #include "third_party/skia/include/core/SkRefCnt.h"
 #include "third_party/skia/include/core/SkRegion.h"
diff --git a/skia/ext/platform_device.h b/skia/ext/platform_device.h
index 5b718d2..628732b 100644
--- a/skia/ext/platform_device.h
+++ b/skia/ext/platform_device.h
@@ -38,12 +38,6 @@
                               PlatformDevice* platform_device);
 SK_API PlatformDevice* GetPlatformDevice(SkBaseDevice* device);
 
-
-#if defined(OS_WIN)
-// Initializes the default settings and colors in a device context.
-SK_API void InitializeDC(HDC context);
-#endif
-
 // A SkBitmapDevice is basically a wrapper around SkBitmap that provides a 
 // surface for SkCanvas to draw into. PlatformDevice provides a surface 
 // Windows can also write to. It also provides functionality to play well 
diff --git a/skia/ext/platform_device_win.cc b/skia/ext/platform_device_win.cc
index 79b2c30b..d1b37ef 100644
--- a/skia/ext/platform_device_win.cc
+++ b/skia/ext/platform_device_win.cc
@@ -11,45 +11,6 @@
 
 namespace skia {
 
-void InitializeDC(HDC context) {
-  // Enables world transformation.
-  // If the GM_ADVANCED graphics mode is set, GDI always draws arcs in the
-  // counterclockwise direction in logical space. This is equivalent to the
-  // statement that, in the GM_ADVANCED graphics mode, both arc control points
-  // and arcs themselves fully respect the device context's world-to-device
-  // transformation.
-  BOOL res = SetGraphicsMode(context, GM_ADVANCED);
-  SkASSERT(res != 0);
-
-  // Enables dithering.
-  res = SetStretchBltMode(context, HALFTONE);
-  SkASSERT(res != 0);
-  // As per SetStretchBltMode() documentation, SetBrushOrgEx() must be called
-  // right after.
-  res = SetBrushOrgEx(context, 0, 0, NULL);
-  SkASSERT(res != 0);
-
-  // Sets up default orientation.
-  res = SetArcDirection(context, AD_CLOCKWISE);
-  SkASSERT(res != 0);
-
-  // Sets up default colors.
-  res = SetBkColor(context, RGB(255, 255, 255));
-  SkASSERT(res != CLR_INVALID);
-  res = SetTextColor(context, RGB(0, 0, 0));
-  SkASSERT(res != CLR_INVALID);
-  res = SetDCBrushColor(context, RGB(255, 255, 255));
-  SkASSERT(res != CLR_INVALID);
-  res = SetDCPenColor(context, RGB(0, 0, 0));
-  SkASSERT(res != CLR_INVALID);
-
-  // Sets up default transparency.
-  res = SetBkMode(context, OPAQUE);
-  SkASSERT(res != 0);
-  res = SetROP2(context, R2_COPYPEN);
-  SkASSERT(res != 0);
-}
-
 PlatformSurface PlatformDevice::BeginPlatformPaint() {
   return 0;
 }
diff --git a/skia/ext/refptr.h b/skia/ext/refptr.h
index a7ba7ffb..93f12204 100644
--- a/skia/ext/refptr.h
+++ b/skia/ext/refptr.h
@@ -6,8 +6,8 @@
 #define SKIA_EXT_REFPTR_H_
 
 #include <algorithm>
+#include <cstddef>
 
-#include "base/move.h"
 #include "third_party/skia/include/core/SkRefCnt.h"
 
 namespace skia {
@@ -52,23 +52,29 @@
 // for you.
 template<typename T>
 class RefPtr {
-  TYPE_WITH_MOVE_CONSTRUCTOR_FOR_CPP_03(RefPtr)
  public:
   RefPtr() : ptr_(nullptr) {}
 
-  RefPtr(decltype(nullptr)) : ptr_(nullptr) {}
+  RefPtr(std::nullptr_t) : ptr_(nullptr) {}
 
+  // Copy constructor.
   RefPtr(const RefPtr& other)
       : ptr_(other.get()) {
     SkSafeRef(ptr_);
   }
 
+  // Copy conversion constructor.
   template<typename U>
   RefPtr(const RefPtr<U>& other)
       : ptr_(other.get()) {
     SkSafeRef(ptr_);
   }
 
+  // Move constructor. This is required in addition to the conversion
+  // constructor below in order for clang to warn about pessimizing moves.
+  RefPtr(RefPtr&& other) : ptr_(other.get()) { other.ptr_ = nullptr; }
+
+  // Move conversion constructor.
   template <typename U>
   RefPtr(RefPtr<U>&& other)
       : ptr_(other.get()) {
@@ -79,7 +85,7 @@
     clear();
   }
 
-  RefPtr& operator=(decltype(nullptr)) {
+  RefPtr& operator=(std::nullptr_t) {
     clear();
     return *this;
   }
@@ -97,7 +103,7 @@
 
   template <typename U>
   RefPtr& operator=(RefPtr<U>&& other) {
-    RefPtr<T> temp(other.Pass());
+    RefPtr<T> temp(std::move(other));
     std::swap(ptr_, temp.ptr_);
     return *this;
   }
diff --git a/skia/ext/refptr_unittest.cc b/skia/ext/refptr_unittest.cc
index a356a64..237f439 100644
--- a/skia/ext/refptr_unittest.cc
+++ b/skia/ext/refptr_unittest.cc
@@ -180,11 +180,11 @@
 TEST(RefPtrTest, PassIntoArguments) {
   // No ref count changes when passing an argument with Pass().
   RefPtr<RefCountCounter> object = skia::AdoptRef(new RefCountCounter);
-  RefPtr<RefCountCounter> object2 = object.Pass();
+  RefPtr<RefCountCounter> object2 = std::move(object);
   auto lambda = [](RefPtr<RefCountCounter> arg) {
     EXPECT_EQ(0, arg->ref_count_changes());
   };
-  lambda(object2.Pass());
+  lambda(std::move(object2));
 }
 
 class DestructionNotifier : public SkRefCnt {
@@ -196,15 +196,6 @@
   bool* flag_;
 };
 
-TEST(RefPtrTest, PassIntoSelf) {
-  bool is_destroyed = false;
-  RefPtr<DestructionNotifier> object =
-      skia::AdoptRef(new DestructionNotifier(&is_destroyed));
-  object = object.Pass();
-  ASSERT_FALSE(is_destroyed);
-  EXPECT_TRUE(object->unique());
-}
-
 TEST(RefPtrTest, Nullptr) {
   RefPtr<SkRefCnt> null(nullptr);
   EXPECT_FALSE(null);
diff --git a/skia/ext/skia_utils_win.cc b/skia/ext/skia_utils_win.cc
index 3089b24..9873373 100644
--- a/skia/ext/skia_utils_win.cc
+++ b/skia/ext/skia_utils_win.cc
@@ -58,5 +58,44 @@
 #endif
 }
 
+void InitializeDC(HDC context) {
+  // Enables world transformation.
+  // If the GM_ADVANCED graphics mode is set, GDI always draws arcs in the
+  // counterclockwise direction in logical space. This is equivalent to the
+  // statement that, in the GM_ADVANCED graphics mode, both arc control points
+  // and arcs themselves fully respect the device context's world-to-device
+  // transformation.
+  BOOL res = SetGraphicsMode(context, GM_ADVANCED);
+  SkASSERT(res != 0);
+
+  // Enables dithering.
+  res = SetStretchBltMode(context, HALFTONE);
+  SkASSERT(res != 0);
+  // As per SetStretchBltMode() documentation, SetBrushOrgEx() must be called
+  // right after.
+  res = SetBrushOrgEx(context, 0, 0, NULL);
+  SkASSERT(res != 0);
+
+  // Sets up default orientation.
+  res = SetArcDirection(context, AD_CLOCKWISE);
+  SkASSERT(res != 0);
+
+  // Sets up default colors.
+  res = SetBkColor(context, RGB(255, 255, 255));
+  SkASSERT(res != CLR_INVALID);
+  res = SetTextColor(context, RGB(0, 0, 0));
+  SkASSERT(res != CLR_INVALID);
+  res = SetDCBrushColor(context, RGB(255, 255, 255));
+  SkASSERT(res != CLR_INVALID);
+  res = SetDCPenColor(context, RGB(0, 0, 0));
+  SkASSERT(res != CLR_INVALID);
+
+  // Sets up default transparency.
+  res = SetBkMode(context, OPAQUE);
+  SkASSERT(res != 0);
+  res = SetROP2(context, R2_COPYPEN);
+  SkASSERT(res != 0);
+}
+
 }  // namespace skia
 
diff --git a/skia/ext/skia_utils_win.h b/skia/ext/skia_utils_win.h
index 379cba12..b116efe 100644
--- a/skia/ext/skia_utils_win.h
+++ b/skia/ext/skia_utils_win.h
@@ -7,6 +7,9 @@
 
 #include "third_party/skia/include/core/SkColor.h"
 
+#include "build/build_config.h"
+#include <windows.h>
+
 struct SkIRect;
 struct SkPoint;
 struct SkRect;
@@ -43,6 +46,9 @@
 // Converts ARGB to COLORREFs (0BGR).
 SK_API COLORREF SkColorToCOLORREF(SkColor color);
 
+// Initializes the default settings and colors in a device context.
+SK_API void InitializeDC(HDC context);
+
 }  // namespace skia
 
 #endif  // SKIA_EXT_SKIA_UTILS_WIN_H_
diff --git a/styleguide/c++/c++11.html b/styleguide/c++/c++11.html
index b11ff54..85ff363 100644
--- a/styleguide/c++/c++11.html
+++ b/styleguide/c++/c++11.html
@@ -303,7 +303,7 @@
 <td><code>v.data()</code></td>
 <td>Returns a pointer to a <code>std::vector</code>'s underlying data, accounting for empty vectors.</td>
 <td><a href="http://en.cppreference.com/w/cpp/container/vector/data">std::vector::data</a></td>
-<td><a href="https://groups.google.com/a/chromium.org/forum/#!topic/cxx/16V7fmtbzok">Discussion thread</a>.</td>
+<td><a href="https://groups.google.com/a/chromium.org/forum/#!topic/cxx/16V7fmtbzok">Discussion thread</a></td>
 </tr>
 
 <tr>
@@ -319,6 +319,14 @@
 </tr>
 
 <tr>
+<td>Conditional Type Selection</td>
+<td><code>std::enable_if</code> and <code>std::conditional</code></td>
+<td>Enables compile-time conditional type selection</td>
+<td><a href="http://en.cppreference.com/w/cpp/types/enable_if">std::enable_if</a> and <a href="http://en.cppreference.com/w/cpp/types/conditional">conditional</a></td>
+<td>Usage should be rare. <a href='https://groups.google.com/a/chromium.org/forum/#!topic/cxx/vCxo4tZNd_M'>Discussion thread</a></td>
+</tr>
+
+<tr>
 <td>Containers containing movable types</td>
 <td><code>vector&lt;scoped_ptr&gt;</code></td>
 <td>Enables containers that contain move-only types like <code>scoped_ptr</code></td>
@@ -335,23 +343,19 @@
 </tr>
 
 <tr>
-<td>Move Semantics</td>
-<td><code>std::move()</code></td>
-<td>Facilitates efficient move operations</td>
-<td><a href="http://en.cppreference.com/w/cpp/utility/move">
-<code>std::move</code> reference</a></td>
-<td>Note: std::move() is allowed but writing your own move constructors is still only allowed in exceptional cases for now, see 'Rvalue References (and Move Semantics)'. <a href='https://groups.google.com/a/chromium.org/forum/#!topic/cxx/x_dWFxJFdbM'>Discussion thread</a></td>
+<td>Move Iterator Adaptor</td>
+<td><code>std::make_move_iterator()</code></td>
+<td>Wraps an iterator so that it moves objects instead of copying them.</td>
+<td><a href="http://en.cppreference.com/w/cpp/iterator/make_move_iterator">std::make_move_iterator</a></td>
+<td>Useful to move objects between containers that contain move-only types like <code>scoped_ptr</code>. <a href="https://groups.google.com/a/chromium.org/forum/#!topic/cxx/lccnUljOHQU">Discussion thread</a></td>
 </tr>
 
 <tr>
-<td>Conditional Type Selection</td>
-<td><code>std::enable_if</code> and <code>std::conditional</code></td>
-<td>Enables compile-time conditional type selection</td>
-<td><a href="http://en.cppreference.com/w/cpp/types/enable_if">
-std::enable_if</a> and
-<a href="http://en.cppreference.com/w/cpp/types/conditional">
-conditional</a></td>
-<td>Usage should be rare.<a href='https://groups.google.com/a/chromium.org/forum/#!topic/cxx/vCxo4tZNd_M'>Discussion thread</a></td>
+<td>Move Semantics</td>
+<td><code>std::move()</code></td>
+<td>Facilitates efficient move operations</td>
+<td><a href="http://en.cppreference.com/w/cpp/utility/move"><code>std::move</code> reference</a></td>
+<td>Note: std::move() is allowed but writing your own move constructors is still only allowed in exceptional cases for now, see 'Rvalue References (and Move Semantics)'. <a href='https://groups.google.com/a/chromium.org/forum/#!topic/cxx/x_dWFxJFdbM'>Discussion thread</a></td>
 </tr>
 
 <tr>
@@ -363,6 +367,14 @@
 <td>Note that not all type traits are available on all platforms (eg std::underlying_type doesn't work in libstdc++4.6). Use judiciously. <a href='https://groups.google.com/a/chromium.org/forum/#!topic/cxx/vCxo4tZNd_M'>Discussion thread</a></td>
 </tr>
 
+<tr>
+<td>Types, functions, and constants from <code>&lt;cmath&gt;</code></td>
+<td><code>std::round()</code>, <code>std::isnan()</code>, and others</td>
+<td>Useful for math-related code</td>
+<td><a href="http://en.cppreference.com/w/cpp/header/cmath"><code>&lt;cmath&gt;</code></a></td>
+<td>Anything in <code>&lt;cmath&gt;</code> is allowed. <a href="https://groups.google.com/a/chromium.org/forum/#!topic/cxx/P-1bFBXMeUk">Discussion thread</a></td>
+</tr>
+
 </tbody>
 </table>
 
@@ -825,14 +837,6 @@
 </tr>
 
 <tr>
-<td>Is Nan</td>
-<td><code>std::isnan()</code></td>
-<td>Determines if a floating point value is not-a-number</td>
-<td><a href="http://en.cppreference.com/w/cpp/numeric/math/isnan">std::isnan</a></td>
-<td></td>
-</tr>
-
-<tr>
 <td>Iterator Operators</td>
 <td><code>std::next()</code> and <code>std::prev()</code></td>
 <td>Copies an iterator and increments or decrements the copy by
diff --git a/sync/BUILD.gn b/sync/BUILD.gn
index edeaf34dd..2f0f730 100644
--- a/sync/BUILD.gn
+++ b/sync/BUILD.gn
@@ -212,6 +212,8 @@
     "internal_api/public/base_transaction.h",
     "internal_api/public/change_record.h",
     "internal_api/public/configure_reason.h",
+    "internal_api/public/data_batch_impl.cc",
+    "internal_api/public/data_batch_impl.h",
     "internal_api/public/data_type_association_stats.cc",
     "internal_api/public/data_type_association_stats.h",
     "internal_api/public/data_type_debug_info_listener.cc",
@@ -268,8 +270,6 @@
     "internal_api/public/shutdown_reason.h",
     "internal_api/public/simple_metadata_change_list.cc",
     "internal_api/public/simple_metadata_change_list.h",
-    "internal_api/public/specifics_only_data_batch.cc",
-    "internal_api/public/specifics_only_data_batch.h",
     "internal_api/public/sync_auth_provider.h",
     "internal_api/public/sync_context.h",
     "internal_api/public/sync_context_proxy.h",
@@ -554,12 +554,14 @@
 static_library("test_support_sync_internal_api") {
   testonly = true
   sources = [
+    "internal_api/public/test/fake_model_type_service.h",
     "internal_api/public/test/fake_sync_manager.h",
     "internal_api/public/test/null_sync_context_proxy.h",
     "internal_api/public/test/sync_manager_factory_for_profile_sync_test.h",
     "internal_api/public/test/test_entry_factory.h",
     "internal_api/public/test/test_internal_components_factory.h",
     "internal_api/public/test/test_user_share.h",
+    "internal_api/test/fake_model_type_service.cc",
     "internal_api/test/fake_sync_manager.cc",
     "internal_api/test/null_sync_context_proxy.cc",
     "internal_api/test/sync_manager_factory_for_profile_sync_test.cc",
@@ -664,6 +666,7 @@
     "internal_api/public/base/ordinal_unittest.cc",
     "internal_api/public/base/unique_position_unittest.cc",
     "internal_api/public/change_record_unittest.cc",
+    "internal_api/public/data_batch_impl_unittest.cc",
     "internal_api/public/engine/model_safe_worker_unittest.cc",
     "internal_api/public/sessions/sync_session_snapshot_unittest.cc",
     "internal_api/public/util/immutable_unittest.cc",
diff --git a/sync/api/data_batch.h b/sync/api/data_batch.h
index f66b5960..68d68e0 100644
--- a/sync/api/data_batch.h
+++ b/sync/api/data_batch.h
@@ -5,15 +5,31 @@
 #ifndef SYNC_API_DATA_BATCH_H_
 #define SYNC_API_DATA_BATCH_H_
 
+#include <algorithm>
+#include <string>
+#include <utility>
+
+#include "base/memory/scoped_ptr.h"
+#include "sync/api/entity_data.h"
 #include "sync/base/sync_export.h"
 
 namespace syncer_v2 {
 
+typedef std::pair<std::string, scoped_ptr<EntityData>> KeyAndData;
+
 // Interface used by the processor to read data requested from the service.
 class SYNC_EXPORT DataBatch {
  public:
   DataBatch() {}
   virtual ~DataBatch() {}
+
+  // Returns if the data batch has another pair or not.
+  virtual bool HasNext() const = 0;
+
+  // Returns a pair of storage key and owned entity data object. Invoking this
+  // method will remove the pair from the batch, and should not be called if
+  // HasNext() returns false.
+  virtual KeyAndData Next() = 0;
 };
 
 }  // namespace syncer_v2
diff --git a/sync/api/entity_data.cc b/sync/api/entity_data.cc
index 8b10b352..0914022 100644
--- a/sync/api/entity_data.cc
+++ b/sync/api/entity_data.cc
@@ -28,7 +28,7 @@
 EntityDataPtr EntityData::Pass() {
   EntityDataPtr target;
   target.swap_value(this);
-  return target.Pass();
+  return target;
 }
 
 void EntityDataTraits::SwapValue(EntityData* dest, EntityData* src) {
diff --git a/sync/api/model_type_service.h b/sync/api/model_type_service.h
index 6ae8bd3f..f7ad9cdd 100644
--- a/sync/api/model_type_service.h
+++ b/sync/api/model_type_service.h
@@ -13,12 +13,9 @@
 #include "sync/api/entity_change.h"
 #include "sync/api/entity_data.h"
 #include "sync/api/model_type_change_processor.h"
+#include "sync/api/sync_error.h"
 #include "sync/base/sync_export.h"
 
-namespace syncer {
-class SyncError;
-}  // namespace syncer
-
 namespace syncer_v2 {
 
 class DataBatch;
diff --git a/sync/api/model_type_store.cc b/sync/api/model_type_store.cc
index 72af0467..17afffc 100644
--- a/sync/api/model_type_store.cc
+++ b/sync/api/model_type_store.cc
@@ -13,6 +13,14 @@
   ModelTypeStoreImpl::CreateInMemoryStoreForTest(callback);
 }
 
+// static
+void ModelTypeStore::CreateStore(
+    const std::string& path,
+    scoped_refptr<base::SequencedTaskRunner> blocking_task_runner,
+    const InitCallback& callback) {
+  ModelTypeStoreImpl::CreateStore(path, blocking_task_runner, callback);
+}
+
 ModelTypeStore::~ModelTypeStore() {}
 
 ModelTypeStore::WriteBatch::WriteBatch() {}
diff --git a/sync/api/model_type_store.h b/sync/api/model_type_store.h
index c37eddd..51ddca6 100644
--- a/sync/api/model_type_store.h
+++ b/sync/api/model_type_store.h
@@ -12,6 +12,10 @@
 #include "base/macros.h"
 #include "sync/base/sync_export.h"
 
+namespace base {
+class SequencedTaskRunner;
+}  // namespace base
+
 namespace syncer_v2 {
 
 // ModelTypeStore is leveldb backed store for model type's data, metadata and
@@ -85,6 +89,21 @@
                               const std::string& global_metadata)>
       ReadMetadataCallback;
 
+  // CreateStore takes |path| and |blocking_task_runner|. Here is how to get
+  // task runner in production code:
+  //
+  // base::SequencedWorkerPool* worker_pool =
+  //     content::BrowserThread::GetBlockingPool();
+  // scoped_refptr<base::SequencedTaskRunner> blocking_task_runner(
+  //     worker_pool->GetSequencedTaskRunnerWithShutdownBehavior(
+  //         worker_pool->GetSequenceToken(),
+  //         base::SequencedWorkerPool::SKIP_ON_SHUTDOWN));
+  //
+  // In test get task runner from MessageLoop::task_runner().
+  static void CreateStore(
+      const std::string& path,
+      scoped_refptr<base::SequencedTaskRunner> blocking_task_runner,
+      const InitCallback& callback);
   // Creates store object backed by in-memory leveldb database. It is used in
   // tests.
   static void CreateInMemoryStoreForTest(const InitCallback& callback);
diff --git a/sync/engine/sync_scheduler_impl.cc b/sync/engine/sync_scheduler_impl.cc
index f40158b..4353be0 100644
--- a/sync/engine/sync_scheduler_impl.cc
+++ b/sync/engine/sync_scheduler_impl.cc
@@ -51,6 +51,7 @@
     case MIGRATION_DONE:
     case THROTTLED:
     case TRANSIENT_ERROR:
+    case PARTIAL_FAILURE:
       return false;
     case NOT_MY_BIRTHDAY:
     case CLIENT_DATA_OBSOLETE:
@@ -67,12 +68,13 @@
       // The notification for this is handled by PostAndProcessHeaders|.
       // Server does no have to send any action for this.
       return true;
-    // Make the default a NOTREACHED. So if a new error is introduced we
-    // think about its expected functionality.
-    default:
+    // Make UNKNOWN_ERROR a NOTREACHED. All the other error should be explicitly
+    // handled.
+    case UNKNOWN_ERROR:
       NOTREACHED();
       return false;
   }
+  return false;
 }
 
 bool IsActionableError(
diff --git a/sync/internal_api/model_type_store_impl.cc b/sync/internal_api/model_type_store_impl.cc
index ba55ef9..fa5a6b7 100644
--- a/sync/internal_api/model_type_store_impl.cc
+++ b/sync/internal_api/model_type_store_impl.cc
@@ -7,6 +7,7 @@
 #include "base/bind.h"
 #include "base/location.h"
 #include "base/logging.h"
+#include "base/sequenced_task_runner.h"
 #include "base/task_runner_util.h"
 #include "base/thread_task_runner_handle.h"
 #include "sync/internal_api/public/model_type_store_backend.h"
@@ -48,7 +49,7 @@
 
 ModelTypeStoreImpl::ModelTypeStoreImpl(
     scoped_ptr<ModelTypeStoreBackend> backend,
-    scoped_refptr<base::TaskRunner> backend_task_runner)
+    scoped_refptr<base::SequencedTaskRunner> backend_task_runner)
     : backend_(backend.Pass()),
       backend_task_runner_(backend_task_runner),
       weak_ptr_factory_(this) {
@@ -63,6 +64,28 @@
 }
 
 // static
+void ModelTypeStoreImpl::CreateStore(
+    const std::string& path,
+    scoped_refptr<base::SequencedTaskRunner> blocking_task_runner,
+    const InitCallback& callback) {
+  DCHECK(!callback.is_null());
+
+  scoped_ptr<ModelTypeStoreBackend> backend(new ModelTypeStoreBackend());
+
+  scoped_ptr<ModelTypeStoreImpl> store(
+      new ModelTypeStoreImpl(backend.Pass(), blocking_task_runner));
+
+  auto task =
+      base::Bind(&ModelTypeStoreBackend::Init,
+                 base::Unretained(store->backend_.get()), path, nullptr);
+  auto reply = base::Bind(&ModelTypeStoreImpl::BackendInitDone, callback,
+                          base::Passed(&store));
+
+  base::PostTaskAndReplyWithResult(blocking_task_runner.get(), FROM_HERE, task,
+                                   reply);
+}
+
+// static
 void ModelTypeStoreImpl::CreateInMemoryStoreForTest(
     const InitCallback& callback) {
   DCHECK(!callback.is_null());
@@ -77,7 +100,7 @@
   backend->TakeEnvOwnership(env.Pass());
 
   // In-memory store backend works on the same thread as test.
-  scoped_refptr<base::TaskRunner> task_runner =
+  scoped_refptr<base::SequencedTaskRunner> task_runner =
       base::ThreadTaskRunnerHandle::Get();
   scoped_ptr<ModelTypeStoreImpl> store(
       new ModelTypeStoreImpl(backend.Pass(), task_runner));
diff --git a/sync/internal_api/public/data_batch_impl.cc b/sync/internal_api/public/data_batch_impl.cc
new file mode 100644
index 0000000..2a614a8
--- /dev/null
+++ b/sync/internal_api/public/data_batch_impl.cc
@@ -0,0 +1,27 @@
+// 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.
+
+#include "sync/internal_api/public/data_batch_impl.h"
+
+namespace syncer_v2 {
+
+DataBatchImpl::DataBatchImpl() {}
+
+DataBatchImpl::~DataBatchImpl() {}
+
+void DataBatchImpl::Put(const std::string& client_key,
+                        scoped_ptr<EntityData> specifics) {
+  key_data_pairs_.push_back(KeyAndData(client_key, std::move(specifics)));
+}
+
+bool DataBatchImpl::HasNext() const {
+  return key_data_pairs_.size() > read_index_;
+}
+
+KeyAndData DataBatchImpl::Next() {
+  DCHECK(HasNext());
+  return std::move(key_data_pairs_[read_index_++]);
+}
+
+}  // namespace syncer_v2
diff --git a/sync/internal_api/public/data_batch_impl.h b/sync/internal_api/public/data_batch_impl.h
new file mode 100644
index 0000000..8b369ba
--- /dev/null
+++ b/sync/internal_api/public/data_batch_impl.h
@@ -0,0 +1,47 @@
+// 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.
+
+#ifndef SYNC_INTERNAL_API_PUBLIC_DATA_BATCH_IMPL_H_
+#define SYNC_INTERNAL_API_PUBLIC_DATA_BATCH_IMPL_H_
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "sync/api/data_batch.h"
+#include "sync/api/entity_data.h"
+
+namespace syncer_v2 {
+
+// An implementation of DataBatch that's purpose is to transfer ownership of
+// EntityData objects. As soon as this batch recieves the EntityData, it owns
+// them until Next() is invoked, when it gives up ownerhsip. Because a vector
+// is used internally, this impl is unaware when duplcate client_keys are used,
+// and it is the caller's job to avoid this.
+class SYNC_EXPORT DataBatchImpl : public DataBatch {
+ public:
+  DataBatchImpl();
+  ~DataBatchImpl() override;
+
+  // Takes ownership of the data tied to a given key used for storage. Put
+  // should be called at most once for any given client_key. Data will be
+  // readable in the same order that they are put into the batch.
+  void Put(const std::string& client_key, scoped_ptr<EntityData> entity_data);
+
+  // DataBatch implementation.
+  bool HasNext() const override;
+  KeyAndData Next() override;
+
+ private:
+  std::vector<KeyAndData> key_data_pairs_;
+  size_t read_index_ = 0;
+
+  DISALLOW_COPY_AND_ASSIGN(DataBatchImpl);
+};
+
+}  // namespace syncer_v2
+
+#endif  // SYNC_INTERNAL_API_PUBLIC_DATA_BATCH_IMPL_H_
diff --git a/sync/internal_api/public/data_batch_impl_unittest.cc b/sync/internal_api/public/data_batch_impl_unittest.cc
new file mode 100644
index 0000000..11be98a
--- /dev/null
+++ b/sync/internal_api/public/data_batch_impl_unittest.cc
@@ -0,0 +1,90 @@
+// 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.
+
+#include "sync/internal_api/public/data_batch_impl.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace syncer_v2 {
+
+TEST(DataBatchImplTest, PutAndNextWithReuse) {
+  EntityData* entity1 = new EntityData();
+  EntityData* entity2 = new EntityData();
+
+  DataBatchImpl batch;
+  EXPECT_FALSE(batch.HasNext());
+
+  batch.Put("one", make_scoped_ptr(entity1));
+  EXPECT_TRUE(batch.HasNext());
+
+  const KeyAndData& pair1 = batch.Next();
+  EXPECT_FALSE(batch.HasNext());
+  EXPECT_EQ("one", pair1.first);
+  EXPECT_EQ(entity1, pair1.second.get());
+
+  batch.Put("two", make_scoped_ptr(entity2));
+  EXPECT_TRUE(batch.HasNext());
+
+  const KeyAndData& pair2 = batch.Next();
+  EXPECT_FALSE(batch.HasNext());
+  EXPECT_EQ("two", pair2.first);
+  EXPECT_EQ(entity2, pair2.second.get());
+}
+
+TEST(DataBatchImplTest, PutAndNextInterleaved) {
+  EntityData* entity1 = new EntityData();
+  EntityData* entity2 = new EntityData();
+  EntityData* entity3 = new EntityData();
+
+  DataBatchImpl batch;
+  EXPECT_FALSE(batch.HasNext());
+
+  batch.Put("one", make_scoped_ptr(entity1));
+  EXPECT_TRUE(batch.HasNext());
+  batch.Put("two", make_scoped_ptr(entity2));
+  EXPECT_TRUE(batch.HasNext());
+
+  const KeyAndData& pair1 = batch.Next();
+  EXPECT_TRUE(batch.HasNext());
+  EXPECT_EQ("one", pair1.first);
+  EXPECT_EQ(entity1, pair1.second.get());
+
+  batch.Put("three", make_scoped_ptr(entity3));
+  EXPECT_TRUE(batch.HasNext());
+
+  const KeyAndData& pair2 = batch.Next();
+  EXPECT_TRUE(batch.HasNext());
+  EXPECT_EQ("two", pair2.first);
+  EXPECT_EQ(entity2, pair2.second.get());
+
+  const KeyAndData& pair3 = batch.Next();
+  EXPECT_FALSE(batch.HasNext());
+  EXPECT_EQ("three", pair3.first);
+  EXPECT_EQ(entity3, pair3.second.get());
+}
+
+TEST(DataBatchImplTest, PutAndNextSharedKey) {
+  EntityData* entity1 = new EntityData();
+  EntityData* entity2 = new EntityData();
+
+  DataBatchImpl batch;
+  EXPECT_FALSE(batch.HasNext());
+
+  batch.Put("same", make_scoped_ptr(entity1));
+  EXPECT_TRUE(batch.HasNext());
+  batch.Put("same", make_scoped_ptr(entity2));
+  EXPECT_TRUE(batch.HasNext());
+
+  const KeyAndData& pair1 = batch.Next();
+  EXPECT_TRUE(batch.HasNext());
+  EXPECT_EQ("same", pair1.first);
+  EXPECT_EQ(entity1, pair1.second.get());
+
+  const KeyAndData& pair2 = batch.Next();
+  EXPECT_FALSE(batch.HasNext());
+  EXPECT_EQ("same", pair2.first);
+  EXPECT_EQ(entity2, pair2.second.get());
+}
+
+}  // namespace syncer_v2
diff --git a/sync/internal_api/public/model_type_store_impl.h b/sync/internal_api/public/model_type_store_impl.h
index d9d0255..227afa0 100644
--- a/sync/internal_api/public/model_type_store_impl.h
+++ b/sync/internal_api/public/model_type_store_impl.h
@@ -10,7 +10,6 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
-#include "base/task_runner.h"
 #include "base/threading/non_thread_safe.h"
 #include "sync/api/model_type_store.h"
 
@@ -29,6 +28,10 @@
  public:
   ~ModelTypeStoreImpl() override;
 
+  static void CreateStore(
+      const std::string& path,
+      scoped_refptr<base::SequencedTaskRunner> blocking_task_runner,
+      const InitCallback& callback);
   static void CreateInMemoryStoreForTest(const InitCallback& callback);
 
   // ModelTypeStore implementation.
@@ -69,8 +72,9 @@
 
   static leveldb::WriteBatch* GetLeveldbWriteBatch(WriteBatch* write_batch);
 
-  ModelTypeStoreImpl(scoped_ptr<ModelTypeStoreBackend> backend,
-                     scoped_refptr<base::TaskRunner> backend_task_runner);
+  ModelTypeStoreImpl(
+      scoped_ptr<ModelTypeStoreBackend> backend,
+      scoped_refptr<base::SequencedTaskRunner> backend_task_runner);
 
   // Callbacks for different calls to ModelTypeStoreBackend.
   void ReadDataDone(const ReadDataCallback& callback,
@@ -95,7 +99,7 @@
   // accomplish this store's dtor posts task to backend thread passing backend
   // ownership to task parameter.
   scoped_ptr<ModelTypeStoreBackend> backend_;
-  scoped_refptr<base::TaskRunner> backend_task_runner_;
+  scoped_refptr<base::SequencedTaskRunner> backend_task_runner_;
 
   base::WeakPtrFactory<ModelTypeStoreImpl> weak_ptr_factory_;
 };
diff --git a/sync/internal_api/public/shared_model_type_processor.h b/sync/internal_api/public/shared_model_type_processor.h
index a7d8f0f..00e914a 100644
--- a/sync/internal_api/public/shared_model_type_processor.h
+++ b/sync/internal_api/public/shared_model_type_processor.h
@@ -12,6 +12,7 @@
 #include "base/memory/weak_ptr.h"
 #include "base/threading/non_thread_safe.h"
 #include "sync/api/model_type_change_processor.h"
+#include "sync/api/model_type_service.h"
 #include "sync/api/sync_error.h"
 #include "sync/base/sync_export.h"
 #include "sync/internal_api/public/base/model_type.h"
@@ -23,7 +24,6 @@
 struct ActivationContext;
 class CommitQueue;
 class ModelTypeEntity;
-class ModelTypeStore;
 
 // A sync component embedded on the synced type's thread that helps to handle
 // communication between sync and model type threads.
@@ -32,8 +32,7 @@
       public ModelTypeChangeProcessor,
       base::NonThreadSafe {
  public:
-  SharedModelTypeProcessor(syncer::ModelType type,
-                           base::WeakPtr<ModelTypeStore> store);
+  SharedModelTypeProcessor(syncer::ModelType type, ModelTypeService* service);
   ~SharedModelTypeProcessor() override;
 
   typedef base::Callback<void(syncer::SyncError, scoped_ptr<ActivationContext>)>
@@ -134,10 +133,10 @@
   // them across restarts, and keep them in sync with our progress markers.
   UpdateMap pending_updates_map_;
 
-  // Store is supplied by model type implementation. SharedModelTypeProcessor
-  // uses store for persisting sync related data (entity state and data type
-  // state).
-  base::WeakPtr<ModelTypeStore> store_;
+  // ModelTypeService linked to this processor.
+  // The service owns this processor instance so the pointer should never
+  // become invalid.
+  ModelTypeService* const service_;
 
   // We use two different WeakPtrFactories because we want the pointers they
   // issue to have different lifetimes.  When asked to disconnect from the sync
diff --git a/sync/internal_api/public/specifics_only_data_batch.cc b/sync/internal_api/public/specifics_only_data_batch.cc
deleted file mode 100644
index 37896a7..0000000
--- a/sync/internal_api/public/specifics_only_data_batch.cc
+++ /dev/null
@@ -1,15 +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.
-
-#include "sync/internal_api/public/specifics_only_data_batch.h"
-
-namespace syncer_v2 {
-
-void SpecificsOnlyDataBatch::Put(
-    const std::string& client_key,
-    scoped_ptr<sync_pb::EntitySpecifics> specifics) {
-  // TODO(skym): Implementation.
-}
-
-}  // namespace syncer_v2
diff --git a/sync/internal_api/public/specifics_only_data_batch.h b/sync/internal_api/public/specifics_only_data_batch.h
deleted file mode 100644
index bb3aa19..0000000
--- a/sync/internal_api/public/specifics_only_data_batch.h
+++ /dev/null
@@ -1,29 +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.
-
-#ifndef SYNC_INTERNAL_API_PUBLIC_SPECIFICS_ONLY_DATA_BATCH_H_
-#define SYNC_INTERNAL_API_PUBLIC_SPECIFICS_ONLY_DATA_BATCH_H_
-
-#include <string>
-
-#include "base/memory/scoped_ptr.h"
-#include "sync/api/data_batch.h"
-#include "sync/protocol/sync.pb.h"
-
-namespace syncer_v2 {
-
-// An implementation of DataBatch that only takes the simplest data from the
-// service. The processor may need to help populate some fields.
-class SpecificsOnlyDataBatch : public DataBatch {
- public:
-  // Takes ownership of the specifics tied to a given key used for storage. Put
-  // should be called at most once for any given client_key. Multiple uses of
-  // the same client_key is currently undefined.
-  void Put(const std::string& client_key,
-           scoped_ptr<sync_pb::EntitySpecifics> specifics);
-};
-
-}  // namespace syncer_v2
-
-#endif  // SYNC_INTERNAL_API_PUBLIC_SPECIFICS_ONLY_DATA_BATCH_H_
diff --git a/sync/internal_api/public/test/fake_model_type_service.h b/sync/internal_api/public/test/fake_model_type_service.h
new file mode 100644
index 0000000..b64ed5d
--- /dev/null
+++ b/sync/internal_api/public/test/fake_model_type_service.h
@@ -0,0 +1,43 @@
+// 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.
+
+#ifndef SYNC_INTERNAL_API_PUBLIC_TEST_FAKE_MODEL_TYPE_SERVICE_H_
+#define SYNC_INTERNAL_API_PUBLIC_TEST_FAKE_MODEL_TYPE_SERVICE_H_
+
+#include "sync/api/data_batch.h"
+#include "sync/api/metadata_batch.h"
+#include "sync/api/metadata_change_list.h"
+#include "sync/api/model_type_service.h"
+
+namespace syncer_v2 {
+
+// A non-functional implementation of ModelTypeService for
+// testing purposes.
+class FakeModelTypeService : public ModelTypeService {
+ public:
+  FakeModelTypeService();
+  ~FakeModelTypeService() override;
+
+  scoped_ptr<MetadataChangeList> CreateMetadataChangeList() override;
+
+  syncer::SyncError MergeSyncData(
+      scoped_ptr<MetadataChangeList> metadata_change_list,
+      EntityDataList entity_data_list) override;
+
+  syncer::SyncError ApplySyncChanges(
+      scoped_ptr<MetadataChangeList> metadata_change_list,
+      EntityChangeList entity_changes) override;
+
+  void LoadMetadata(MetadataCallback callback) override;
+
+  void GetData(ClientKeyList client_keys, DataCallback callback) override;
+
+  void GetAllData(DataCallback callback) override;
+
+  std::string GetClientTag(const EntityData& entity_data) override;
+};
+
+}  // namespace syncer_v2
+
+#endif  // SYNC_INTERNAL_API_PUBLIC_TEST_FAKE_MODEL_TYPE_SERVICE_H_
diff --git a/sync/internal_api/public/util/proto_value_ptr.h b/sync/internal_api/public/util/proto_value_ptr.h
index a4f4fc0..164f2db 100644
--- a/sync/internal_api/public/util/proto_value_ptr.h
+++ b/sync/internal_api/public/util/proto_value_ptr.h
@@ -53,8 +53,6 @@
 // value.
 template <typename T, typename Traits = DefaultProtoValuePtrTraits<T>>
 class ProtoValuePtr {
-  TYPE_WITH_MOVE_CONSTRUCTOR_FOR_CPP_03(ProtoValuePtr)
-
  private:
   // Immutable shareable ref-counted wrapper that embeds the value.
   class Wrapper : public base::RefCountedThreadSafe<Wrapper> {
diff --git a/sync/internal_api/shared_model_type_processor.cc b/sync/internal_api/shared_model_type_processor.cc
index db511dfa..97cf8e5 100644
--- a/sync/internal_api/shared_model_type_processor.cc
+++ b/sync/internal_api/shared_model_type_processor.cc
@@ -69,15 +69,16 @@
 
 }  // namespace
 
-SharedModelTypeProcessor::SharedModelTypeProcessor(
-    syncer::ModelType type,
-    base::WeakPtr<ModelTypeStore> store)
+SharedModelTypeProcessor::SharedModelTypeProcessor(syncer::ModelType type,
+                                                   ModelTypeService* service)
     : type_(type),
       is_enabled_(false),
       is_connected_(false),
-      store_(store),
+      service_(service),
       weak_ptr_factory_for_ui_(this),
-      weak_ptr_factory_for_sync_(this) {}
+      weak_ptr_factory_for_sync_(this) {
+  DCHECK(service);
+}
 
 SharedModelTypeProcessor::~SharedModelTypeProcessor() {}
 
@@ -272,8 +273,8 @@
     ModelTypeEntity* entity = nullptr;
     EntityMap::const_iterator it = entities_.find(client_tag_hash);
     if (it == entities_.end()) {
-      // TODO(stanisc): crbug/561821: Get client_tag from the service.
-      std::string client_tag = client_tag_hash;
+      // Let the service define |client_tag| based on the entity data.
+      std::string client_tag = service_->GetClientTag(data);
 
       scoped_ptr<ModelTypeEntity> scoped_entity = ModelTypeEntity::CreateNew(
           client_tag, client_tag_hash, data.id, data.creation_time);
diff --git a/sync/internal_api/shared_model_type_processor_unittest.cc b/sync/internal_api/shared_model_type_processor_unittest.cc
index 2cc99981..6bbed17 100644
--- a/sync/internal_api/shared_model_type_processor_unittest.cc
+++ b/sync/internal_api/shared_model_type_processor_unittest.cc
@@ -11,6 +11,7 @@
 #include "sync/internal_api/public/activation_context.h"
 #include "sync/internal_api/public/base/model_type.h"
 #include "sync/internal_api/public/non_blocking_sync_common.h"
+#include "sync/internal_api/public/test/fake_model_type_service.h"
 #include "sync/protocol/sync.pb.h"
 #include "sync/syncable/syncable_util.h"
 #include "sync/test/engine/mock_commit_queue.h"
@@ -41,7 +42,8 @@
 // - Writes to permanent storage. (TODO)
 // - Callbacks into the model. (TODO)
 // - Requests to the sync thread.  Tested with MockCommitQueue.
-class SharedModelTypeProcessorTest : public ::testing::Test {
+class SharedModelTypeProcessorTest : public ::testing::Test,
+                                     public FakeModelTypeService {
  public:
   SharedModelTypeProcessorTest();
   ~SharedModelTypeProcessorTest() override;
@@ -129,6 +131,9 @@
   void StartDone(syncer::SyncError error,
                  scoped_ptr<ActivationContext> context);
 
+  // FakeModelTypeService overrides.
+  std::string GetClientTag(const EntityData& entity_data) override;
+
   // This sets ThreadTaskRunnerHandle on the current thread, which the type
   // processor will pick up as the sync task runner.
   base::MessageLoop sync_loop_;
@@ -145,9 +150,7 @@
 SharedModelTypeProcessorTest::SharedModelTypeProcessorTest()
     : mock_queue_(new MockCommitQueue()),
       mock_queue_ptr_(mock_queue_),
-      type_processor_(
-          new SharedModelTypeProcessor(kModelType,
-                                       base::WeakPtr<ModelTypeStore>())) {}
+      type_processor_(new SharedModelTypeProcessor(kModelType, this)) {}
 
 SharedModelTypeProcessorTest::~SharedModelTypeProcessorTest() {}
 
@@ -338,6 +341,12 @@
   return specifics;
 }
 
+std::string SharedModelTypeProcessorTest::GetClientTag(
+    const EntityData& entity_data) {
+  // The tag is the preference name - see GenerateSpecifics.
+  return entity_data.specifics.preference().name();
+}
+
 size_t SharedModelTypeProcessorTest::GetNumCommitRequestLists() {
   return mock_queue_->GetNumCommitRequestLists();
 }
diff --git a/sync/internal_api/sync_context_proxy_impl_unittest.cc b/sync/internal_api/sync_context_proxy_impl_unittest.cc
index 880bb0b..171d9b2 100644
--- a/sync/internal_api/sync_context_proxy_impl_unittest.cc
+++ b/sync/internal_api/sync_context_proxy_impl_unittest.cc
@@ -11,6 +11,7 @@
 #include "sync/internal_api/public/base/model_type.h"
 #include "sync/internal_api/public/shared_model_type_processor.h"
 #include "sync/internal_api/public/sync_context.h"
+#include "sync/internal_api/public/test/fake_model_type_service.h"
 #include "sync/internal_api/sync_context_proxy_impl.h"
 #include "sync/sessions/model_type_registry.h"
 #include "sync/test/engine/mock_nudge_handler.h"
@@ -19,7 +20,7 @@
 
 namespace syncer_v2 {
 
-class SyncContextProxyImplTest : public ::testing::Test {
+class SyncContextProxyImplTest : public ::testing::Test, FakeModelTypeService {
  public:
   SyncContextProxyImplTest()
       : sync_task_runner_(base::ThreadTaskRunnerHandle::Get()),
@@ -54,8 +55,7 @@
   }
 
   scoped_ptr<SharedModelTypeProcessor> CreateModelTypeProcessor() {
-    return make_scoped_ptr(new SharedModelTypeProcessor(
-        syncer::THEMES, base::WeakPtr<ModelTypeStore>()));
+    return make_scoped_ptr(new SharedModelTypeProcessor(syncer::THEMES, this));
   }
 
  private:
diff --git a/sync/internal_api/test/fake_model_type_service.cc b/sync/internal_api/test/fake_model_type_service.cc
new file mode 100644
index 0000000..d31388f
--- /dev/null
+++ b/sync/internal_api/test/fake_model_type_service.cc
@@ -0,0 +1,41 @@
+// 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.
+
+#include "sync/internal_api/public/test/fake_model_type_service.h"
+
+namespace syncer_v2 {
+
+FakeModelTypeService::FakeModelTypeService() {}
+
+FakeModelTypeService::~FakeModelTypeService() {}
+
+scoped_ptr<MetadataChangeList>
+FakeModelTypeService::CreateMetadataChangeList() {
+  return scoped_ptr<MetadataChangeList>();
+}
+
+syncer::SyncError FakeModelTypeService::MergeSyncData(
+    scoped_ptr<MetadataChangeList> metadata_change_list,
+    EntityDataList entity_data_list) {
+  return syncer::SyncError();
+}
+
+syncer::SyncError FakeModelTypeService::ApplySyncChanges(
+    scoped_ptr<MetadataChangeList> metadata_change_list,
+    EntityChangeList entity_changes) {
+  return syncer::SyncError();
+}
+
+void FakeModelTypeService::LoadMetadata(MetadataCallback callback) {}
+
+void FakeModelTypeService::GetData(ClientKeyList client_keys,
+                                   DataCallback callback) {}
+
+void FakeModelTypeService::GetAllData(DataCallback callback) {}
+
+std::string FakeModelTypeService::GetClientTag(const EntityData& entity_data) {
+  return std::string();
+}
+
+}  // namespace syncer_v2
diff --git a/sync/protocol/sync_protocol_error.cc b/sync/protocol/sync_protocol_error.cc
index 163f64f0..992f6ac 100644
--- a/sync/protocol/sync_protocol_error.cc
+++ b/sync/protocol/sync_protocol_error.cc
@@ -19,7 +19,6 @@
     ENUM_CASE(THROTTLED);
     ENUM_CASE(CLEAR_PENDING);
     ENUM_CASE(TRANSIENT_ERROR);
-    ENUM_CASE(NON_RETRIABLE_ERROR);
     ENUM_CASE(MIGRATION_DONE);
     ENUM_CASE(INVALID_CREDENTIAL);
     ENUM_CASE(DISABLED_BY_ADMIN);
diff --git a/sync/protocol/sync_protocol_error.h b/sync/protocol/sync_protocol_error.h
index 47c4f84e..d65fd243 100644
--- a/sync/protocol/sync_protocol_error.h
+++ b/sync/protocol/sync_protocol_error.h
@@ -28,10 +28,6 @@
   // Server cannot service the request now.
   TRANSIENT_ERROR,
 
-  // Server does not wish the client to retry any more until the action has
-  // been taken.
-  NON_RETRIABLE_ERROR,
-
   // Indicates the datatypes have been migrated and the client should resync
   // them to get the latest progress markers.
   MIGRATION_DONE,
diff --git a/sync/sessions/model_type_registry_unittest.cc b/sync/sessions/model_type_registry_unittest.cc
index 6db266ae..30ffbff 100644
--- a/sync/sessions/model_type_registry_unittest.cc
+++ b/sync/sessions/model_type_registry_unittest.cc
@@ -9,6 +9,7 @@
 #include "sync/internal_api/public/activation_context.h"
 #include "sync/internal_api/public/base/model_type.h"
 #include "sync/internal_api/public/shared_model_type_processor.h"
+#include "sync/internal_api/public/test/fake_model_type_service.h"
 #include "sync/sessions/model_type_registry.h"
 #include "sync/test/engine/fake_model_worker.h"
 #include "sync/test/engine/mock_nudge_handler.h"
@@ -17,17 +18,8 @@
 
 namespace syncer {
 
-namespace {
-
-scoped_ptr<syncer_v2::SharedModelTypeProcessor> MakeModelTypeProcessor(
-    ModelType type) {
-  return make_scoped_ptr(new syncer_v2::SharedModelTypeProcessor(
-      type, base::WeakPtr<syncer_v2::ModelTypeStore>()));
-}
-
-}  // namespace
-
-class ModelTypeRegistryTest : public ::testing::Test {
+class ModelTypeRegistryTest : public ::testing::Test,
+                              syncer_v2::FakeModelTypeService {
  public:
   ModelTypeRegistryTest();
   void SetUp() override;
@@ -54,6 +46,12 @@
     return context.Pass();
   }
 
+ protected:
+  scoped_ptr<syncer_v2::SharedModelTypeProcessor> MakeModelTypeProcessor(
+      ModelType type) {
+    return make_scoped_ptr(new syncer_v2::SharedModelTypeProcessor(type, this));
+  }
+
  private:
   syncable::Directory* directory();
 
diff --git a/sync/sync.gyp b/sync/sync.gyp
index 2de3160..e9f991d 100644
--- a/sync/sync.gyp
+++ b/sync/sync.gyp
@@ -265,6 +265,8 @@
         'internal_api/public/change_record.h',
         'internal_api/public/configure_reason.h',
         'internal_api/public/connection_status.h',
+        'internal_api/public/data_batch_impl.h',
+        'internal_api/public/data_batch_impl.cc',
         'internal_api/public/data_type_association_stats.cc',
         'internal_api/public/data_type_association_stats.h',
         'internal_api/public/data_type_debug_info_listener.cc',
@@ -321,8 +323,6 @@
         'internal_api/public/shutdown_reason.h',
         'internal_api/public/simple_metadata_change_list.cc',
         'internal_api/public/simple_metadata_change_list.h',
-        'internal_api/public/specifics_only_data_batch.h',
-        'internal_api/public/specifics_only_data_batch.cc',
         'internal_api/public/sync_auth_provider.h',
         'internal_api/public/sync_context.h',
         'internal_api/public/sync_context_proxy.h',
diff --git a/sync/sync_tests.gypi b/sync/sync_tests.gypi
index bc0c307..079812c 100644
--- a/sync/sync_tests.gypi
+++ b/sync/sync_tests.gypi
@@ -183,12 +183,14 @@
         'test_support_sync_core',
       ],
       'sources': [
+        'internal_api/public/test/fake_model_type_service.h',
         'internal_api/public/test/fake_sync_manager.h',
         'internal_api/public/test/null_sync_context_proxy.h',
         'internal_api/public/test/sync_manager_factory_for_profile_sync_test.h',
         'internal_api/public/test/test_entry_factory.h',
         'internal_api/public/test/test_internal_components_factory.h',
         'internal_api/public/test/test_user_share.h',
+        'internal_api/test/fake_model_type_service.cc',
         'internal_api/test/fake_sync_manager.cc',
         'internal_api/test/null_sync_context_proxy.cc',
         'internal_api/test/sync_manager_factory_for_profile_sync_test.cc',
@@ -310,6 +312,7 @@
         'internal_api/public/base/ordinal_unittest.cc',
         'internal_api/public/base/unique_position_unittest.cc',
         'internal_api/public/change_record_unittest.cc',
+        'internal_api/public/data_batch_impl_unittest.cc',
         'internal_api/public/engine/model_safe_worker_unittest.cc',
         'internal_api/public/sessions/sync_session_snapshot_unittest.cc',
         'internal_api/public/util/immutable_unittest.cc',
diff --git a/testing/android/driver/java/AndroidManifest.xml b/testing/android/driver/java/AndroidManifest.xml
index d67f9cd..16c70e20 100644
--- a/testing/android/driver/java/AndroidManifest.xml
+++ b/testing/android/driver/java/AndroidManifest.xml
@@ -11,6 +11,7 @@
       android:versionName="1.0">
 
     <uses-sdk android:minSdkVersion="16" android:targetSdkVersion="23" />
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
 
     <application android:label="OnDeviceInstrumentationDriver" />
 
@@ -18,6 +19,4 @@
             android:targetPackage="org.chromium.test.driver"
             android:label="OnDeviceInstrumentationDriver"/>
 
-    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
-
 </manifest>
diff --git a/testing/android/native_test/java/src/org/chromium/native_test/NativeTestActivity.java b/testing/android/native_test/java/src/org/chromium/native_test/NativeTestActivity.java
index ebe0ce3..bdba1e0 100644
--- a/testing/android/native_test/java/src/org/chromium/native_test/NativeTestActivity.java
+++ b/testing/android/native_test/java/src/org/chromium/native_test/NativeTestActivity.java
@@ -60,8 +60,10 @@
     private void parseArgumentsFromIntent(Intent intent) {
         Log.i(TAG, "Extras:");
         Bundle extras = intent.getExtras();
-        for (String s : extras.keySet()) {
-            Log.i(TAG, "  %s", s);
+        if (extras != null) {
+            for (String s : extras.keySet()) {
+                Log.i(TAG, "  %s", s);
+            }
         }
 
         mCommandLineFilePath = intent.getStringExtra(EXTRA_COMMAND_LINE_FILE);
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index 76b7dcc..c54c5a356 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -5702,7 +5702,7 @@
       {
         "args": [
           "--site-per-process",
-          "--gtest_filter=-BrowserTest.InterstitialCancelsGuestViewDialogs:BrowserTest.OtherRedirectsDontForkProcess:BrowserTest.WindowOpenClose:ChromeRenderProcessHostTest.*:ChromeRenderProcessHostTestWithCommandLine.*:ErrorPageTest.*:ExtensionApiTest.ContentScriptOtherExtensions:ExtensionApiTest.Tabs2:ExtensionApiTest.TabsOnUpdated:ExtensionOptionsApiTest.ExtensionCanEmbedOwnOptions:IsolatedAppTest.*:MimeHandlerViewTest.*:*PDFExtensionTest.*:PhishingDOMFeatureExtractorTest.SubFrames:PrerenderBrowserTest.*:ProcessManagementTest.*:RedirectTest.ClientEmptyReferer:ReferrerPolicyTest.HttpsRedirect:*.RestoreWebUISettings:SSLUITest.TestGoodFrameNavigation:SSLUITest.TestMarkNonSecureAs:WebNavigationApiTest.CrossProcessFragment:WebNavigationApiTest.ServerRedirectSingleProcess:WebNavigationApiTest.CrossProcessHistory:WebViewDPITest.*:WebViewPluginTest.*:WebViewTest.AcceptTouchEvents:WebViewTest.IndexedDBIsolation:WebViewTest.ScreenCoordinates:WebViewTest.ContextMenusAPI_PreventDefault:WebViewTest.TestContextMenu:WebViewTest.NestedGuestContainerBounds:WebViewFocusTest.*:WebViewNewWindowTest.*:WebViewVisibilityTest.*:*.NavigateFromNTPToOptionsInSameTab:*.TabMove:*.WhitelistedExtension:*.NewTabPageURL:*.HomepageLocation:RestoreOnStartupPolicyTestInstance/RestoreOnStartupPolicyTest.RunTest*:PhishingClassifierDelegateTest.*:WebUIWebViewBrowserTest*:WebRtcBrowserTest.RunsAudioVideoWebRTCCallInTwoTabs:SingleProcessTracingBrowserTest.TestMemoryInfra"
+          "--gtest_filter=-BrowserTest.InterstitialCancelsGuestViewDialogs:BrowserTest.OtherRedirectsDontForkProcess:BrowserTest.WindowOpenClose:ChromeRenderProcessHostTest.*:ChromeRenderProcessHostTestWithCommandLine.*:ErrorPageTest.*:ExtensionApiTest.Tabs2:ExtensionApiTest.TabsOnUpdated:ExtensionOptionsApiTest.ExtensionCanEmbedOwnOptions:IsolatedAppTest.*:MimeHandlerViewTest.*:*PDFExtensionTest.*:PhishingDOMFeatureExtractorTest.SubFrames:PrerenderBrowserTest.*:ProcessManagementTest.*:RedirectTest.ClientEmptyReferer:ReferrerPolicyTest.HttpsRedirect:*.RestoreWebUISettings:SSLUITest.TestGoodFrameNavigation:SSLUITest.TestMarkNonSecureAs:WebNavigationApiTest.CrossProcessFragment:WebNavigationApiTest.ServerRedirectSingleProcess:WebNavigationApiTest.CrossProcessHistory:WebViewDPITest.*:WebViewPluginTest.*:WebViewTest.AcceptTouchEvents:WebViewTest.IndexedDBIsolation:WebViewTest.ScreenCoordinates:WebViewTest.ContextMenusAPI_PreventDefault:WebViewTest.TestContextMenu:WebViewTest.NestedGuestContainerBounds:WebViewFocusTest.*:WebViewNewWindowTest.*:WebViewVisibilityTest.*:*.NavigateFromNTPToOptionsInSameTab:*.TabMove:*.WhitelistedExtension:*.NewTabPageURL:*.HomepageLocation:RestoreOnStartupPolicyTestInstance/RestoreOnStartupPolicyTest.RunTest*:PhishingClassifierDelegateTest.*:WebUIWebViewBrowserTest*:WebRtcBrowserTest.RunsAudioVideoWebRTCCallInTwoTabs:SingleProcessTracingBrowserTest.TestMemoryInfra"
         ],
         "test": "browser_tests"
       },
@@ -5733,7 +5733,7 @@
       {
         "args": [
           "--site-per-process",
-          "--gtest_filter=-BrowserTest.InterstitialCancelsGuestViewDialogs:BrowserTest.OtherRedirectsDontForkProcess:BrowserTest.WindowOpenClose:ChromeRenderProcessHostTest.*:ChromeRenderProcessHostTestWithCommandLine.*:ErrorPageTest.*:ExtensionApiTest.ContentScriptOtherExtensions:ExtensionApiTest.Tabs2:ExtensionApiTest.TabsOnUpdated:ExtensionOptionsApiTest.ExtensionCanEmbedOwnOptions:IsolatedAppTest.*:MimeHandlerViewTest.*:*PDFExtensionTest.*:PhishingDOMFeatureExtractorTest.SubFrames:PrerenderBrowserTest.*:ProcessManagementTest.*:RedirectTest.ClientEmptyReferer:ReferrerPolicyTest.HttpsRedirect:*.RestoreWebUISettings:SSLUITest.TestGoodFrameNavigation:SSLUITest.TestMarkNonSecureAs:WebNavigationApiTest.CrossProcessFragment:WebNavigationApiTest.ServerRedirectSingleProcess:WebNavigationApiTest.CrossProcessHistory:WebViewDPITest.*:WebViewPluginTest.*:WebViewTest.AcceptTouchEvents:WebViewTest.IndexedDBIsolation:WebViewTest.ScreenCoordinates:WebViewTest.ContextMenusAPI_PreventDefault:WebViewTest.TestContextMenu:WebViewTest.NestedGuestContainerBounds:WebViewFocusTest.*:WebViewNewWindowTest.*:WebViewVisibilityTest.*:*.NavigateFromNTPToOptionsInSameTab:*.TabMove:*.WhitelistedExtension:*.NewTabPageURL:*.HomepageLocation:RestoreOnStartupPolicyTestInstance/RestoreOnStartupPolicyTest.RunTest*:PhishingClassifierDelegateTest.*:WebUIWebViewBrowserTest*:WebRtcBrowserTest.RunsAudioVideoWebRTCCallInTwoTabs:SingleProcessTracingBrowserTest.TestMemoryInfra"
+          "--gtest_filter=-BrowserTest.InterstitialCancelsGuestViewDialogs:BrowserTest.OtherRedirectsDontForkProcess:BrowserTest.WindowOpenClose:ChromeRenderProcessHostTest.*:ChromeRenderProcessHostTestWithCommandLine.*:ErrorPageTest.*:ExtensionApiTest.Tabs2:ExtensionApiTest.TabsOnUpdated:ExtensionOptionsApiTest.ExtensionCanEmbedOwnOptions:IsolatedAppTest.*:MimeHandlerViewTest.*:*PDFExtensionTest.*:PhishingDOMFeatureExtractorTest.SubFrames:PrerenderBrowserTest.*:ProcessManagementTest.*:RedirectTest.ClientEmptyReferer:ReferrerPolicyTest.HttpsRedirect:*.RestoreWebUISettings:SSLUITest.TestGoodFrameNavigation:SSLUITest.TestMarkNonSecureAs:WebNavigationApiTest.CrossProcessFragment:WebNavigationApiTest.ServerRedirectSingleProcess:WebNavigationApiTest.CrossProcessHistory:WebViewDPITest.*:WebViewPluginTest.*:WebViewTest.AcceptTouchEvents:WebViewTest.IndexedDBIsolation:WebViewTest.ScreenCoordinates:WebViewTest.ContextMenusAPI_PreventDefault:WebViewTest.TestContextMenu:WebViewTest.NestedGuestContainerBounds:WebViewFocusTest.*:WebViewNewWindowTest.*:WebViewVisibilityTest.*:*.NavigateFromNTPToOptionsInSameTab:*.TabMove:*.WhitelistedExtension:*.NewTabPageURL:*.HomepageLocation:RestoreOnStartupPolicyTestInstance/RestoreOnStartupPolicyTest.RunTest*:PhishingClassifierDelegateTest.*:WebUIWebViewBrowserTest*:WebRtcBrowserTest.RunsAudioVideoWebRTCCallInTwoTabs:SingleProcessTracingBrowserTest.TestMemoryInfra"
         ],
         "test": "browser_tests"
       },
diff --git a/testing/libfuzzer/fuzzers/BUILD.gn b/testing/libfuzzer/fuzzers/BUILD.gn
index e36175e..3d52292 100644
--- a/testing/libfuzzer/fuzzers/BUILD.gn
+++ b/testing/libfuzzer/fuzzers/BUILD.gn
@@ -227,3 +227,18 @@
     "//third_party/zlib",
   ]
 }
+
+test("pdfium_fuzzer") {
+  sources = [
+    "pdfium_fuzzer.cc",
+  ]
+  deps = [
+    "//testing/libfuzzer:libfuzzer_main",
+    "//third_party/pdfium",
+    "//third_party/pdfium:test_support",
+    "//v8",
+    "//v8:v8_libplatform",
+  ]
+  configs += [ "//third_party/pdfium:pdfium_config" ]
+  configs += [ "//v8:external_config" ]
+}
diff --git a/testing/libfuzzer/fuzzers/pdfium_fuzzer.cc b/testing/libfuzzer/fuzzers/pdfium_fuzzer.cc
new file mode 100644
index 0000000..9a735f5
--- /dev/null
+++ b/testing/libfuzzer/fuzzers/pdfium_fuzzer.cc
@@ -0,0 +1,189 @@
+// Copyright (c) 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.
+
+// This fuzzer is simplified & cleaned up pdfium/samples/pdfium_test.cc
+
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <list>
+#include <sstream>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "third_party/pdfium/public/fpdf_dataavail.h"
+#include "third_party/pdfium/public/fpdf_ext.h"
+#include "third_party/pdfium/public/fpdf_formfill.h"
+#include "third_party/pdfium/public/fpdf_text.h"
+#include "third_party/pdfium/public/fpdfview.h"
+#include "third_party/pdfium/testing/test_support.h"
+
+#include "v8/include/v8.h"
+
+static int ExampleAppAlert(IPDF_JSPLATFORM*, FPDF_WIDESTRING, FPDF_WIDESTRING,
+    int, int) {
+  return 0;
+}
+
+static void ExampleDocGotoPage(IPDF_JSPLATFORM*, int pageNumber) { }
+
+static void ExampleUnsupportedHandler(UNSUPPORT_INFO*, int type) { }
+
+
+FPDF_BOOL Is_Data_Avail(FX_FILEAVAIL* pThis, size_t offset, size_t size) {
+  return true;
+}
+
+static void Add_Segment(FX_DOWNLOADHINTS* pThis, size_t offset, size_t size) { }
+
+static bool RenderPage(const FPDF_DOCUMENT& doc,
+    const FPDF_FORMHANDLE& form,
+    const int page_index) {
+  FPDF_PAGE page = FPDF_LoadPage(doc, page_index);
+  if (!page) {
+    return false;
+  }
+  FPDF_TEXTPAGE text_page = FPDFText_LoadPage(page);
+  FORM_OnAfterLoadPage(page, form);
+  FORM_DoPageAAction(page, form, FPDFPAGE_AACTION_OPEN);
+
+  double scale = 1.0;
+  int width = static_cast<int>(FPDF_GetPageWidth(page) * scale);
+  int height = static_cast<int>(FPDF_GetPageHeight(page) * scale);
+
+  FPDF_BITMAP bitmap = FPDFBitmap_Create(width, height, 0);
+  if (!bitmap) {
+    return false;
+  }
+
+  FPDFBitmap_FillRect(bitmap, 0, 0, width, height, 0xFFFFFFFF);
+  FPDF_RenderPageBitmap(bitmap, page, 0, 0, width, height, 0, 0);
+
+  FPDF_FFLDraw(form, bitmap, page, 0, 0, width, height, 0, 0);
+
+  FPDFBitmap_Destroy(bitmap);
+  FORM_DoPageAAction(page, form, FPDFPAGE_AACTION_CLOSE);
+  FORM_OnBeforeClosePage(page, form);
+  FPDFText_ClosePage(text_page);
+  FPDF_ClosePage(page);
+  return true;
+}
+
+static void RenderPdf(const char* pBuf, size_t len) {
+  IPDF_JSPLATFORM platform_callbacks;
+  memset(&platform_callbacks, '\0', sizeof(platform_callbacks));
+  platform_callbacks.version = 3;
+  platform_callbacks.app_alert = ExampleAppAlert;
+  platform_callbacks.Doc_gotoPage = ExampleDocGotoPage;
+
+  FPDF_FORMFILLINFO form_callbacks;
+  memset(&form_callbacks, '\0', sizeof(form_callbacks));
+  form_callbacks.version = 1;
+  form_callbacks.m_pJsPlatform = &platform_callbacks;
+
+  TestLoader loader(pBuf, len);
+  FPDF_FILEACCESS file_access;
+  memset(&file_access, '\0', sizeof(file_access));
+  file_access.m_FileLen = static_cast<unsigned long>(len);
+  file_access.m_GetBlock = TestLoader::GetBlock;
+  file_access.m_Param = &loader;
+
+  FX_FILEAVAIL file_avail;
+  memset(&file_avail, '\0', sizeof(file_avail));
+  file_avail.version = 1;
+  file_avail.IsDataAvail = Is_Data_Avail;
+
+  FX_DOWNLOADHINTS hints;
+  memset(&hints, '\0', sizeof(hints));
+  hints.version = 1;
+  hints.AddSegment = Add_Segment;
+
+  FPDF_DOCUMENT doc;
+  int nRet = PDF_DATA_NOTAVAIL;
+  bool bIsLinearized = false;
+  FPDF_AVAIL pdf_avail = FPDFAvail_Create(&file_avail, &file_access);
+
+  if (FPDFAvail_IsLinearized(pdf_avail) == PDF_LINEARIZED) {
+    doc = FPDFAvail_GetDocument(pdf_avail, nullptr);
+    if (doc) {
+      while (nRet == PDF_DATA_NOTAVAIL) {
+        nRet = FPDFAvail_IsDocAvail(pdf_avail, &hints);
+      }
+      if (nRet == PDF_DATA_ERROR) {
+        return;
+      }
+      nRet = FPDFAvail_IsFormAvail(pdf_avail, &hints);
+      if (nRet == PDF_FORM_ERROR || nRet == PDF_FORM_NOTAVAIL) {
+        return;
+      }
+      bIsLinearized = true;
+    }
+  } else {
+    doc = FPDF_LoadCustomDocument(&file_access, nullptr);
+  }
+
+  if (!doc) {
+    FPDFAvail_Destroy(pdf_avail);
+    return;
+  }
+
+  (void)FPDF_GetDocPermissions(doc);
+
+  FPDF_FORMHANDLE form = FPDFDOC_InitFormFillEnvironment(doc, &form_callbacks);
+  FPDF_SetFormFieldHighlightColor(form, 0, 0xFFE4DD);
+  FPDF_SetFormFieldHighlightAlpha(form, 100);
+
+  FORM_DoDocumentJSAction(form);
+  FORM_DoDocumentOpenAction(form);
+
+  int page_count = FPDF_GetPageCount(doc);
+
+  for (int i = 0; i < page_count; ++i) {
+    if (bIsLinearized) {
+      nRet = PDF_DATA_NOTAVAIL;
+      while (nRet == PDF_DATA_NOTAVAIL) {
+        nRet = FPDFAvail_IsPageAvail(pdf_avail, i, &hints);
+      }
+      if (nRet == PDF_DATA_ERROR) {
+        return;
+      }
+    }
+    RenderPage(doc, form, i);
+  }
+
+  FORM_DoDocumentAAction(form, FPDFDOC_AACTION_WC);
+  FPDFDOC_ExitFormFillEnvironment(form);
+  FPDF_CloseDocument(doc);
+  FPDFAvail_Destroy(pdf_avail);
+}
+
+static v8::Platform* Init() {
+  v8::Platform* platform;
+  InitializeV8ForPDFium(&platform);
+
+  auto config = new FPDF_LIBRARY_CONFIG();
+  config->version = 2;
+  config->m_pUserFontPaths = nullptr;
+  config->m_pIsolate = nullptr;
+  config->m_v8EmbedderSlot = 0;
+  FPDF_InitLibraryWithConfig(config);
+
+  auto unsuppored_info = new UNSUPPORT_INFO();
+  memset(unsuppored_info, '\0', sizeof(*unsuppored_info));
+  unsuppored_info->version = 1;
+  unsuppored_info->FSDK_UnSupport_Handler = ExampleUnsupportedHandler;
+  FSDK_SetUnSpObjProcessHandler(unsuppored_info);
+
+  return platform;
+}
+
+static v8::Platform* platform = Init();
+
+extern "C" int LLVMFuzzerTestOneInput(const unsigned char* data, size_t size) {
+  RenderPdf(reinterpret_cast<const char*>(data), size);
+  return 0;
+}
diff --git a/testing/scripts/mojo_apptests.py b/testing/scripts/mojo_apptests.py
index 49b855da2..70f32c80 100755
--- a/testing/scripts/mojo_apptests.py
+++ b/testing/scripts/mojo_apptests.py
@@ -34,7 +34,7 @@
 
 
 def main_compile_targets(args):
-  json.dump(['mandoline:tests'], args.output)
+  json.dump(['mandoline:tests', 'mash/wm:tests'], args.output)
 
 
 if __name__ == '__main__':
diff --git a/third_party/WebKit/LayoutTests/NeverFixTests b/third_party/WebKit/LayoutTests/NeverFixTests
index 5c4da0a..10c6dda 100644
--- a/third_party/WebKit/LayoutTests/NeverFixTests
+++ b/third_party/WebKit/LayoutTests/NeverFixTests
@@ -145,7 +145,6 @@
 
 # Chrome Linux doesn't support NPAPI plugins anymore.
 [ Linux ] http/tests/plugins/interrupted-get-url.html [ WontFix ]
-[ Linux ] http/tests/plugins/third-party-cookie-accept-policy.html [ WontFix ]
 [ Linux ] plugins/mouse-click-plugin-clears-selection.html [ WontFix ]
 
 # Missing Chrome Mac support, will start working when we move to harfbuzz on mac.
diff --git a/third_party/WebKit/LayoutTests/SlowTests b/third_party/WebKit/LayoutTests/SlowTests
index 10edb315..8560bd0d 100644
--- a/third_party/WebKit/LayoutTests/SlowTests
+++ b/third_party/WebKit/LayoutTests/SlowTests
@@ -9,7 +9,7 @@
 
 crbug.com/24182 [ Debug ] storage/indexeddb/objectstore-cursor.html [ Slow ]
 crbug.com/24182 storage/indexeddb/mozilla/test_objectStore_openKeyCursor.html [ Slow ]
-crbug.com/24182 [ Linux Win Debug ] editing/selection/move-by-word-visually-mac.html [ Slow ]
+crbug.com/24182 editing/selection/move-by-word-visually-mac.html [ Slow ]
 crbug.com/24182 editing/selection/move-by-word-visually-multi-line.html [ Slow ]
 crbug.com/24182 [ Win ] virtual/gpu/fast/canvas/webgl/canvas-test.html [ Slow ]
 crbug.com/24182 [ Win ] virtual/gpu/fast/canvas/webgl/framebuffer-object-attachment.html [ Slow ]
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index 399b6a37..4238e835 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -134,12 +134,10 @@
 crbug.com/520612 [ Linux ] fullscreen/anonymous-block-merge-crash.html [ Pass Timeout ]
 crbug.com/520613 http/tests/cache/freshness-header.html [ Failure Pass ]
 crbug.com/520614 http/tests/w3c/webperf/submission/Intel/resource-timing/test_resource_timing_buffer_size_restriction.html [ Failure Pass ]
-crbug.com/520617 [ Mac ] webaudio/audiochannelmerger-disconnect.html [ Failure Pass ]
 crbug.com/520619 [ Android Mac Linux XP Win7 ] webexposed/global-interface-listing.html [ Pass Timeout ]
 crbug.com/520194 http/tests/xmlhttprequest/timeout/xmlhttprequest-timeout-worker-overridesexpires.html [ Failure Pass ]
 crbug.com/520199 [ Mac ] plugins/plugin-initiate-popup-window.html [ Failure Pass ]
 crbug.com/520200 [ XP ] svg/batik/text/smallFonts.svg [ Failure Timeout ]
-crbug.com/520203 webaudio/audiobuffersource-late-start.html [ Failure Pass Timeout ]
 crbug.com/518967 [ Win7 ] http/tests/htmlimports/csp-import-block-but-nonce-nested.html [ Failure Pass Timeout ]
 crbug.com/448461 http/tests/loading/simple-subframe.html [ Failure Pass Timeout ]
 crbug.com/339597 http/tests/navigation/back-to-redirect-with-frame.php [ Pass Timeout ]
@@ -180,7 +178,6 @@
 crbug.com/519001 storage/indexeddb/pending-version-change-stuck-works-with-terminate.html [ Pass Timeout ]
 crbug.com/519002 storage/indexeddb/pending-version-change-stuck.html [ Pass Timeout ]
 crbug.com/519003 [ Mac ] svg/batik/text/xmlSpace.svg [ Failure Pass ]
-crbug.com/519005 webaudio/stereopannernode-no-glitch.html [ Pass Timeout ]
 crbug.com/410949 http/tests/security/local-image-from-remote-whitelisted.html [ Failure Pass ]
 crbug.com/356828 fast/dom/gc-dom-tree-lifetime.html [ Pass Timeout ]
 crbug.com/518902 accessibility/AccessibilityScrollbar-leak.html [ Failure Pass ]
@@ -544,7 +541,6 @@
 crbug.com/318978 [ Linux ] http/tests/security/contentSecurityPolicy/object-src-none-allowed.html [ Skip ]
 crbug.com/318978 [ Linux ] http/tests/security/contentSecurityPolicy/object-src-url-blocked.html [ Skip ]
 crbug.com/318978 [ Linux ] http/tests/security/contentSecurityPolicy/plugin-in-iframe-with-csp.html [ Skip ]
-crbug.com/318978 [ Linux ] http/tests/security/frameNavigation/xss-DENIED-plugin-navigation.html [ Skip ]
 crbug.com/318978 [ Linux ] permissionclient/plugin-permission.html [ Skip ]
 crbug.com/318978 [ Linux ] plugins/ [ Skip ]
 
@@ -806,7 +802,8 @@
 
 crbug.com/390377 [ Release ] fast/dom/private_script_unittest.html [ Skip ]
 
-crbug.com/546512 http/tests/security/w3c/cross-origin-objects.html [ NeedsManualRebaseline ]
+# TODO(jkummerow): Re-enable after V8-side patch rolls in.
+crbug.com/565934 http/tests/security/cross-frame-access-enumeration.html [ Skip ]
 
 crbug.com/357427 http/tests/workers/terminate-during-sync-operation-file.html [ Crash Pass Slow Timeout ]
 crbug.com/357427 http/tests/workers/terminate-during-sync-operation-filesystem.html [ Crash Pass Slow Timeout ]
@@ -1306,8 +1303,6 @@
 # The Win10 result for fast/text/emoji-font-fallback-win.html does not match the description
 crbug.com/527044 [ Win10 ] fast/text/emoji-font-fallback-win.html [ Failure ]
 
-crbug.com/525065 webaudio/audionode-disconnect-audioparam.html [ Failure Pass ]
-
 crbug.com/525296 fast/css/font-load-while-styleresolver-missing.html [ Crash Failure Pass ]
 
 crbug.com/240576 fullscreen/api/element-ready-check-containing-iframe.html [ Timeout Failure Pass ]
diff --git a/third_party/WebKit/LayoutTests/accessibility/description-calc-inputs.html b/third_party/WebKit/LayoutTests/accessibility/description-calc-inputs.html
index e82530d..44c70e2 100644
--- a/third_party/WebKit/LayoutTests/accessibility/description-calc-inputs.html
+++ b/third_party/WebKit/LayoutTests/accessibility/description-calc-inputs.html
@@ -108,6 +108,25 @@
 }, "placeholder overrides title as the accessible description.");
 </script>
 
+<div class="container">
+    <input id="text8" type="text" aria-describedby="describedby8">
+    <p id="describedby8">
+        Described
+        <br>
+        By
+    </p>
+</div>
+
+<script>
+test(function(t) {
+    var axTextInput8 = accessibilityController.accessibleElementById("text8");
+    assert_equals(axTextInput8.name, "");
+    assert_equals(axTextInput8.nameFrom, "");
+    assert_equals(axTextInput8.description, "Described By");
+    assert_equals(axTextInput8.descriptionFrom, "relatedElement");
+}, "aria-describedby does not include newlines.");
+</script>
+
 <script>
 if (window.testRunner)
     document.body.className = "hideAllContainers";
diff --git a/third_party/WebKit/LayoutTests/accessibility/display-none-change.html b/third_party/WebKit/LayoutTests/accessibility/display-none-change.html
index 9697088..8b247767e 100644
--- a/third_party/WebKit/LayoutTests/accessibility/display-none-change.html
+++ b/third_party/WebKit/LayoutTests/accessibility/display-none-change.html
@@ -13,7 +13,7 @@
     // Ensure that it's valid.
     var axLabel = axButton.nameElementAtIndex(0);
     assert_equals(axLabel.isValid, true);
-    assert_equals(axLabel.name, 'AriaLabel');
+    assert_equals(axLabel.role, 'AXRole: AXLabel');
 
     // Now un-hide the label.
     var label = document.getElementById('label');
@@ -36,7 +36,7 @@
     assert_equals(axLabel.isValid, false);
     assert_equals(axLabel2.isValid, false);
     assert_equals(axLabel3.isValid, true);
-    assert_equals(axLabel3.name, 'AriaLabel');
+    assert_equals(axLabel3.role, 'AXRole: AXLabel');
     assert_equals(axLabel.isEqual(axLabel3), false);
     assert_equals(axLabel2.isEqual(axLabel3), false);
 }, "Accessibility objects for display:none elements");
diff --git a/third_party/WebKit/LayoutTests/accessibility/element-role-mapping-normal-expected.txt b/third_party/WebKit/LayoutTests/accessibility/element-role-mapping-normal-expected.txt
index b486e5f..22929f9 100644
--- a/third_party/WebKit/LayoutTests/accessibility/element-role-mapping-normal-expected.txt
+++ b/third_party/WebKit/LayoutTests/accessibility/element-role-mapping-normal-expected.txt
@@ -130,7 +130,9 @@
             AXRole: AXStaticText "Text that appears under aside"
                 AXRole: AXInlineTextBox "Text that appears under aside"
     AXRole: AXPre
-        AXRole: AXStaticText "Text in a    pre element "
+        AXRole: AXStaticText "Text in a    pre
+element
+"
             AXRole: AXInlineTextBox "Text in a    pre"
             AXRole: AXInlineTextBox "
 "
diff --git a/third_party/WebKit/LayoutTests/accessibility/img-alt-tag-only-whitespace-expected.txt b/third_party/WebKit/LayoutTests/accessibility/img-alt-tag-only-whitespace-expected.txt
index b9b8cc0..52170f7 100644
--- a/third_party/WebKit/LayoutTests/accessibility/img-alt-tag-only-whitespace-expected.txt
+++ b/third_party/WebKit/LayoutTests/accessibility/img-alt-tag-only-whitespace-expected.txt
@@ -1,4 +1,4 @@
-CONSOLE MESSAGE: line 26: Image description:    Image 
+CONSOLE MESSAGE: line 26: Image description:  Image 
 
 
 
diff --git a/third_party/WebKit/LayoutTests/accessibility/name-calc-visibility.html b/third_party/WebKit/LayoutTests/accessibility/name-calc-visibility.html
new file mode 100644
index 0000000..00bab2e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/accessibility/name-calc-visibility.html
@@ -0,0 +1,102 @@
+<!DOCTYPE HTML>
+<script src="../resources/testharness.js"></script>
+<script src="../resources/testharnessreport.js"></script>
+
+<style>
+.hideAllContainers .container {
+    display: none;
+}
+</style>
+
+<div id="link1" class="container" tabIndex=0 role="link">
+    <p>1</p>
+    <table>
+        <tr><td>2</td></tr>
+        <tr><td style="visibility: hidden">3</td></tr>
+        <tr><td style="display:none">4</td></tr>
+        <tr style="visibility: hidden"><td>5</td></tr>
+        <tr style="display: none"><td>6</td></tr>
+    </table>
+    <p>7</p>
+</div>
+
+<script>
+test(function(t) {
+    var axLink1 = accessibilityController.accessibleElementById("link1");
+    assert_equals(axLink1.name, "1 2 7");
+}, "Visibility: 'hidden' and display: 'none' inside ARIA link");
+</script>
+
+<div class="container">
+    <input id="input2" aria-labelledby="label2">
+
+    <div id="label2">
+        <p>1</p>
+        <table>
+            <tr><td>2</td></tr>
+            <tr><td style="visibility: hidden">3</td></tr>
+            <tr><td style="display:none">4</td></tr>
+            <tr style="visibility: hidden"><td>5</td></tr>
+            <tr style="display: none"><td>6</td></tr>
+        </table>
+        <p>7</p>
+    </div>
+</div>
+
+<script>
+test(function(t) {
+    var axInput2 = accessibilityController.accessibleElementById("input2");
+    assert_equals(axInput2.name, "1 2 7");
+}, "Visibility: 'hidden' and display: 'none' inside aria-labelledby label subtree");
+</script>
+
+<div class="container">
+    <input id="input3" aria-labelledby="3a 3b 3c 3d 3e 3f 3g">
+
+    <p id="3a">1</p>
+    <table>
+        <tr><td id="3b">2</td></tr>
+        <tr><td id="3c" style="visibility: hidden">3</td></tr>
+        <tr><td id="3d" style="display:none">4</td></tr>
+        <tr id="3e" style="visibility: hidden"><td>5</td></tr>
+        <tr id="3f" style="display: none"><td>6</td></tr>
+    </table>
+    <p id="3g">7</p>
+</div>
+
+<script>
+test(function(t) {
+    var axInput3 = accessibilityController.accessibleElementById("input3");
+    assert_equals(axInput3.name, "1 2 3 4 6 7");
+}, "Visibility: 'hidden' and display: 'none' referenced directly by aria-labelledby");
+</script>
+
+<div class="container">
+    <input id="input4" aria-labelledby="label4">
+
+    <div style="display: none">
+        <div id="label4">
+            <p>1</p>
+            <table>
+                <tr><td>2</td></tr>
+                <tr><td style="visibility: hidden">3</td></tr>
+                <tr><td style="display:none">4</td></tr>
+                <tr style="visibility: hidden"><td>5</td></tr>
+                <tr style="display: none"><td>6</td></tr>
+            </table>
+            <p>7</p>
+        </div>
+    </div>
+</div>
+
+<script>
+test(function(t) {
+    var axInput4 = accessibilityController.accessibleElementById("input4");
+    assert_equals(axInput4.name, " 1 2 7 ");
+}, "Visibility: 'hidden' and display: 'none' inside aria-labelledby label subtree, where entire label subtree is display: 'none'");
+</script>
+
+<script>
+if (window.testRunner)
+    document.body.className = "hideAllContainers";
+</script>
diff --git a/third_party/WebKit/LayoutTests/fast/borders/border-image-inherits-with-border-expected.html b/third_party/WebKit/LayoutTests/fast/borders/border-image-inherits-with-border-expected.html
new file mode 100644
index 0000000..78537d9c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/borders/border-image-inherits-with-border-expected.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<style>
+  #parent {
+    border: solid;
+    border-image-source: url('resources/border-image.png');
+    border-image-slice: 10%;
+    border-image-width: 2;
+    border-image-outset: 1;
+    border-image-repeat: repeat;
+
+  }
+
+  #child {
+    border: inherit;
+    border-image-source: inherit;
+    border-image-slice: inherit;
+    border-image-width: inherit;
+    border-image-outset: inherit;
+    border-image-repeat: inherit;
+  }
+</style>
+<div id="parent">
+  <p>Parent with border-image</p>
+  <span id="child">Child - should inherit border-image</span>
+</div>
diff --git a/third_party/WebKit/LayoutTests/fast/borders/border-image-inherits-with-border.html b/third_party/WebKit/LayoutTests/fast/borders/border-image-inherits-with-border.html
new file mode 100644
index 0000000..e08d229
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/borders/border-image-inherits-with-border.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<style>
+  #parent {
+    border: solid;
+    border-image-source: url('resources/border-image.png');
+    border-image-slice: 10%;
+    border-image-width: 2;
+    border-image-outset: 1;
+    border-image-repeat: repeat;
+  }
+
+  #child {
+    border: inherit;
+  }
+</style>
+<div id="parent">
+  <p>Parent with border-image</p>
+  <span id="child">Child - should inherit border-image</span>
+</div>
diff --git a/third_party/WebKit/LayoutTests/fast/css/containment/contain-parse-and-apply-expected.txt b/third_party/WebKit/LayoutTests/fast/css/containment/contain-parse-and-apply-expected.txt
new file mode 100644
index 0000000..04212e1
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/containment/contain-parse-and-apply-expected.txt
@@ -0,0 +1,26 @@
+PASS getContainValue('#none') is "none"
+PASS getContainValue('#style') is "style"
+PASS getContainValue('#layout') is "layout"
+PASS getContainValue('#paint') is "paint"
+PASS getContainValue('#strict') is "strict"
+PASS computedContainValue(children[i]) is "none"
+PASS computedContainValue(children[i]) is "none"
+PASS computedContainValue(children[i]) is "none"
+PASS computedContainValue(children[i]) is "none"
+PASS computedContainValue(children[i]) is "none"
+PASS getContainValue('#test') is "strict"
+PASS getContainValue('#test') is "layout paint"
+PASS getContainValue('#test') is "strict"
+PASS getContainValue('#test') is "none"
+PASS getContainValue('#test') is "none"
+PASS getContainValue('#test') is "none"
+PASS getContainValue('#test') is "none"
+PASS getContainValue('#test') is "none"
+PASS getContainValue('#test') is "style paint"
+PASS getContainValue('#test') is "style paint"
+PASS getContainValue('#test') is "style paint"
+PASS getContainValue('#test') is "style paint"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/third_party/WebKit/LayoutTests/fast/css/containment/contain-parse-and-apply.html b/third_party/WebKit/LayoutTests/fast/css/containment/contain-parse-and-apply.html
new file mode 100644
index 0000000..5c1bd257
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/containment/contain-parse-and-apply.html
@@ -0,0 +1,75 @@
+<!DOCTYPE html>
+<style>
+#none { contain: none; }
+#style { contain: style; }
+#layout { contain: layout; }
+#paint { contain: paint; }
+#strict { contain: strict; }
+</style>
+<body>
+<div id="none"><div></div></div>
+<div id="style"><div></div></div>
+<div id="layout"><div></div></div>
+<div id="paint"><div></div></div>
+<div id="strict"><div></div></div>
+<div id="test"></div>
+<script src="../../../resources/js-test.js"></script>
+<script>
+function computedContainValue(element) {
+    return window.getComputedStyle(element).contain;
+}
+function getContainValue(query)
+{
+    var element = document.querySelector(query);
+    return computedContainValue(element);
+}
+
+shouldBeEqualToString("getContainValue('#none')", "none");
+shouldBeEqualToString("getContainValue('#style')", "style");
+shouldBeEqualToString("getContainValue('#layout')", "layout");
+shouldBeEqualToString("getContainValue('#paint')", "paint");
+shouldBeEqualToString("getContainValue('#strict')", "strict");
+
+var children = document.querySelectorAll("div > div");
+for (var i = 0; i < children.length; i++) {
+    shouldBeEqualToString("computedContainValue(children[i])", "none");
+}
+
+var test = document.querySelector('#test');
+
+test.style.setProperty("contain", "layout paint style");
+shouldBeEqualToString("getContainValue('#test')", "strict");
+
+test.style.setProperty("contain", "layout paint");
+shouldBeEqualToString("getContainValue('#test')", "layout paint");
+
+test.style.setProperty("contain", "strict");
+shouldBeEqualToString("getContainValue('#test')", "strict");
+
+test.style.setProperty("contain", "none");
+shouldBeEqualToString("getContainValue('#test')", "none");
+
+test.style.setProperty("contain", "layout layout");
+shouldBeEqualToString("getContainValue('#test')", "none");
+
+test.style.setProperty("contain", "strict layout");
+shouldBeEqualToString("getContainValue('#test')", "none");
+
+test.style.setProperty("contain", "paint strict");
+shouldBeEqualToString("getContainValue('#test')", "none");
+
+test.style.setProperty("contain", "paint layout style paint");
+shouldBeEqualToString("getContainValue('#test')", "none");
+
+test.style.setProperty("contain", "style paint");
+shouldBeEqualToString("getContainValue('#test')", "style paint");
+
+test.style.setProperty("contain", "none strict");
+shouldBeEqualToString("getContainValue('#test')", "style paint");
+
+test.style.setProperty("contain", "strict strict");
+shouldBeEqualToString("getContainValue('#test')", "style paint");
+
+test.style.setProperty("contain", "strict none");
+shouldBeEqualToString("getContainValue('#test')", "style paint");
+</script>
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/fast/css/invalidation/add-first-line-style-expected.html b/third_party/WebKit/LayoutTests/fast/css/invalidation/add-first-line-style-expected.html
new file mode 100644
index 0000000..5d83472
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/invalidation/add-first-line-style-expected.html
@@ -0,0 +1,4 @@
+<!DOCTYPE html>
+<!-- This expectation is wrong because of crbug.com/564239.
+     Correct expectation should be with style="color: green". -->
+<div>This text should be green.</div>
diff --git a/third_party/WebKit/LayoutTests/fast/css/invalidation/add-first-line-style.html b/third_party/WebKit/LayoutTests/fast/css/invalidation/add-first-line-style.html
new file mode 100644
index 0000000..fb7a62b7
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/invalidation/add-first-line-style.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<style id="style">
+#target::first-line { color: green }
+</style>
+<script>
+document.getElementById('style').disabled = true;
+</script>
+<div id="target">This text should be green.</div>
+<script src="../../../resources/run-after-layout-and-paint.js"></script>
+<script>
+runAfterLayoutAndPaint(function() {
+  document.getElementById('style').disabled = false;
+}, true);
+</script>
diff --git a/third_party/WebKit/LayoutTests/fast/css/invalidation/first-line-change-inline-color-expected.html b/third_party/WebKit/LayoutTests/fast/css/invalidation/first-line-change-inline-color-expected.html
new file mode 100644
index 0000000..09c518e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/invalidation/first-line-change-inline-color-expected.html
@@ -0,0 +1,4 @@
+<!DOCTYPE html>
+<!-- This expectation is wrong because of crbug.com/562418.
+     The inner span should have style="color: green". -->
+<p style="color: red">Red <span>This text should be green.</span> Red</p>
diff --git a/third_party/WebKit/LayoutTests/fast/css/invalidation/first-line-change-inline-color-inherited-expected.html b/third_party/WebKit/LayoutTests/fast/css/invalidation/first-line-change-inline-color-inherited-expected.html
new file mode 100644
index 0000000..09c518e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/invalidation/first-line-change-inline-color-inherited-expected.html
@@ -0,0 +1,4 @@
+<!DOCTYPE html>
+<!-- This expectation is wrong because of crbug.com/562418.
+     The inner span should have style="color: green". -->
+<p style="color: red">Red <span>This text should be green.</span> Red</p>
diff --git a/third_party/WebKit/LayoutTests/fast/css/invalidation/first-line-change-inline-color-inherited.html b/third_party/WebKit/LayoutTests/fast/css/invalidation/first-line-change-inline-color-inherited.html
new file mode 100644
index 0000000..917847a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/invalidation/first-line-change-inline-color-inherited.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<style>
+  #block { color: green; }
+  #block::first-line { color: red; }
+  .green { color: green; }
+</style>
+<div id="block">
+  <div>
+    <p>Red <span id="t"><span>This text should be green.<span></span> Red</p>
+  </div>
+</div>
+<script src="../../resources/run-after-layout-and-paint.js"></script>
+<script>
+runAfterLayoutAndPaint(function() {
+  document.getElementById('t').className = 'green';
+}, true);
+</script>
diff --git a/third_party/WebKit/LayoutTests/fast/css/invalidation/first-line-change-inline-color.html b/third_party/WebKit/LayoutTests/fast/css/invalidation/first-line-change-inline-color.html
new file mode 100644
index 0000000..c147ad6b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/invalidation/first-line-change-inline-color.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<style>
+  #block { color: green; }
+  #block::first-line { color: red; }
+  .green { color: green; }
+</style>
+<div id="block">
+  <div>
+    <p>Red <span id="t">This text should be green.</span> Red</p>
+  </div>
+</div>
+<script src="../../resources/run-after-layout-and-paint.js"></script>
+<script>
+runAfterLayoutAndPaint(function() {
+  document.getElementById('t').className = 'green';
+}, true);
+</script>
diff --git a/third_party/WebKit/LayoutTests/fast/css/invalidation/remove-first-line-style-expected.html b/third_party/WebKit/LayoutTests/fast/css/invalidation/remove-first-line-style-expected.html
new file mode 100644
index 0000000..a8463d6
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/invalidation/remove-first-line-style-expected.html
@@ -0,0 +1,4 @@
+<!DOCTYPE html>
+<!-- This expectation is wrong because of crbug.com/564239.
+     Correct expectation should be style="color: green". -->
+<div style="color: red">This text should be green.</div>
diff --git a/third_party/WebKit/LayoutTests/fast/css/invalidation/remove-first-line-style.html b/third_party/WebKit/LayoutTests/fast/css/invalidation/remove-first-line-style.html
new file mode 100644
index 0000000..9d3455c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/invalidation/remove-first-line-style.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<style id="style">
+#target::first-line { color: red }
+</style>
+<div id="target" style="color: green">This text should be green.</div>
+<script src="../../../resources/run-after-layout-and-paint.js"></script>
+<script>
+runAfterLayoutAndPaint(function() {
+  document.getElementById('style').disabled = true;
+}, true);
+</script>
diff --git a/third_party/WebKit/LayoutTests/fast/css/parsing-object-position-expected.txt b/third_party/WebKit/LayoutTests/fast/css/parsing-object-position-expected.txt
index 9e0f568..97c6918 100644
--- a/third_party/WebKit/LayoutTests/fast/css/parsing-object-position-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/css/parsing-object-position-expected.txt
@@ -13,29 +13,29 @@
 PASS testComputedStyle("object-position: bottom 20px right 12px;") is "calc(-12px + 100%) calc(-20px + 100%)"
 PASS test("object-position: inherit;") is "inherit"
 PASS test("object-position: initial;") is "initial"
-PASS test("object-position: left;") is "0% 50%"
-PASS test("object-position: top;") is "50% 0%"
-PASS test("object-position: top right;") is "100% 0%"
-PASS test("object-position: right top;") is "100% 0%"
-PASS test("object-position: center center;") is "50% 50%"
-PASS test("object-position: center;") is "50% 50%"
-PASS test("object-position: bottom center;") is "50% 100%"
-PASS test("object-position: left center;") is "0% 50%"
-PASS test("object-position: bottom center;") is "50% 100%"
-PASS test("object-position: center left;") is "0% 50%"
-PASS test("object-position: center bottom;") is "50% 100%"
-PASS test("object-position: 100px;") is "100px 50%"
+PASS test("object-position: left;") is "left center"
+PASS test("object-position: top;") is "center top"
+PASS test("object-position: top right;") is "right top"
+PASS test("object-position: right top;") is "right top"
+PASS test("object-position: center center;") is "center center"
+PASS test("object-position: center;") is "center center"
+PASS test("object-position: bottom center;") is "center bottom"
+PASS test("object-position: left center;") is "left center"
+PASS test("object-position: bottom center;") is "center bottom"
+PASS test("object-position: center left;") is "left center"
+PASS test("object-position: center bottom;") is "center bottom"
+PASS test("object-position: 100px;") is "100px center"
 PASS test("object-position: 100px 100px;") is "100px 100px"
 PASS test("object-position: 100px 200px;") is "100px 200px"
 PASS test("object-position: -50% 0;") is "-50% 0px"
 PASS test("object-position: 3em 0;") is "3em 0px"
-PASS test("object-position: left 33px;") is "0% 33px"
-PASS test("object-position: center 33px;") is "50% 33px"
-PASS test("object-position: 33px center;") is "33px 50%"
-PASS test("object-position: 33px bottom;") is "33px 100%"
+PASS test("object-position: left 33px;") is "left 33px"
+PASS test("object-position: center 33px;") is "center 33px"
+PASS test("object-position: 33px center;") is "33px center"
+PASS test("object-position: 33px bottom;") is "33px bottom"
 PASS test("object-position: 1vh 1vw;") is "1vh 1vw"
-PASS test("object-position: left 20px center;") is "left 20px top 50%"
-PASS test("object-position: center bottom 25%;") is "left 50% bottom 25%"
+PASS test("object-position: left 20px center;") is "left 20px center"
+PASS test("object-position: center bottom 25%;") is "center bottom 25%"
 PASS test("object-position: bottom 20px right 12px;") is "right 12px bottom 20px"
 PASS test("object-position: 100px 100px 100px;") is ""
 PASS test("object-position: 100px 100px 200px 200px;") is ""
diff --git a/third_party/WebKit/LayoutTests/fast/css/parsing-object-position.html b/third_party/WebKit/LayoutTests/fast/css/parsing-object-position.html
index b4a32af..41c72c1 100644
--- a/third_party/WebKit/LayoutTests/fast/css/parsing-object-position.html
+++ b/third_party/WebKit/LayoutTests/fast/css/parsing-object-position.html
@@ -40,29 +40,29 @@
 
             shouldBeEqualToString('test("object-position: inherit;")', 'inherit');
             shouldBeEqualToString('test("object-position: initial;")', 'initial');
-            shouldBeEqualToString('test("object-position: left;")', '0% 50%');
-            shouldBeEqualToString('test("object-position: top;")', '50% 0%');
-            shouldBeEqualToString('test("object-position: top right;")', '100% 0%');
-            shouldBeEqualToString('test("object-position: right top;")', '100% 0%');
-            shouldBeEqualToString('test("object-position: center center;")', '50% 50%');
-            shouldBeEqualToString('test("object-position: center;")', '50% 50%');
-            shouldBeEqualToString('test("object-position: bottom center;")', '50% 100%');
-            shouldBeEqualToString('test("object-position: left center;")', '0% 50%');
-            shouldBeEqualToString('test("object-position: bottom center;")', '50% 100%');
-            shouldBeEqualToString('test("object-position: center left;")', '0% 50%');
-            shouldBeEqualToString('test("object-position: center bottom;")', '50% 100%');
-            shouldBeEqualToString('test("object-position: 100px;")', '100px 50%');
+            shouldBeEqualToString('test("object-position: left;")', 'left center');
+            shouldBeEqualToString('test("object-position: top;")', 'center top');
+            shouldBeEqualToString('test("object-position: top right;")', 'right top');
+            shouldBeEqualToString('test("object-position: right top;")', 'right top');
+            shouldBeEqualToString('test("object-position: center center;")', 'center center');
+            shouldBeEqualToString('test("object-position: center;")', 'center center');
+            shouldBeEqualToString('test("object-position: bottom center;")', 'center bottom');
+            shouldBeEqualToString('test("object-position: left center;")', 'left center');
+            shouldBeEqualToString('test("object-position: bottom center;")', 'center bottom');
+            shouldBeEqualToString('test("object-position: center left;")', 'left center');
+            shouldBeEqualToString('test("object-position: center bottom;")', 'center bottom');
+            shouldBeEqualToString('test("object-position: 100px;")', '100px center');
             shouldBeEqualToString('test("object-position: 100px 100px;")', '100px 100px');
             shouldBeEqualToString('test("object-position: 100px 200px;")', '100px 200px');
             shouldBeEqualToString('test("object-position: -50% 0;")', '-50% 0px');
             shouldBeEqualToString('test("object-position: 3em 0;")', '3em 0px');
-            shouldBeEqualToString('test("object-position: left 33px;")', '0% 33px');
-            shouldBeEqualToString('test("object-position: center 33px;")', '50% 33px');
-            shouldBeEqualToString('test("object-position: 33px center;")', '33px 50%');
-            shouldBeEqualToString('test("object-position: 33px bottom;")', '33px 100%');
+            shouldBeEqualToString('test("object-position: left 33px;")', 'left 33px');
+            shouldBeEqualToString('test("object-position: center 33px;")', 'center 33px');
+            shouldBeEqualToString('test("object-position: 33px center;")', '33px center');
+            shouldBeEqualToString('test("object-position: 33px bottom;")', '33px bottom');
             shouldBeEqualToString('test("object-position: 1vh 1vw;")', '1vh 1vw');
-            shouldBeEqualToString('test("object-position: left 20px center;")', 'left 20px top 50%');
-            shouldBeEqualToString('test("object-position: center bottom 25%;")', 'left 50% bottom 25%');
+            shouldBeEqualToString('test("object-position: left 20px center;")', 'left 20px center');
+            shouldBeEqualToString('test("object-position: center bottom 25%;")', 'center bottom 25%');
             shouldBeEqualToString('test("object-position: bottom 20px right 12px;")', 'right 12px bottom 20px');
 
             shouldBeEqualToString('test("object-position: 100px 100px 100px;")', '');
diff --git a/third_party/WebKit/LayoutTests/fast/css/variables/matched-properties-cache-is-disabled.html b/third_party/WebKit/LayoutTests/fast/css/variables/matched-properties-cache-is-disabled.html
new file mode 100644
index 0000000..4f85b082
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/variables/matched-properties-cache-is-disabled.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<style>
+header {
+  --x: black;
+}
+
+main {
+  --x: green;
+}
+
+button {
+  background: var(--x);
+}
+</style>
+
+<header><button id='a'></button></header>
+<main><button id='b'></button></header>
+<script>
+test(function() {
+  assert_equals(getComputedStyle(a).backgroundColor, 'rgb(0, 0, 0)');
+  assert_equals(getComputedStyle(b).backgroundColor, 'rgb(0, 128, 0)');
+}, "uninherited properties don't reuse values when set to variables.");
+
+</script>
diff --git a/third_party/WebKit/LayoutTests/fast/dom/HTMLLinkElement/link-preload-validity-expected.txt b/third_party/WebKit/LayoutTests/fast/dom/HTMLLinkElement/link-preload-validity-expected.txt
index 80eca1b..e0f262e 100644
--- a/third_party/WebKit/LayoutTests/fast/dom/HTMLLinkElement/link-preload-validity-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/dom/HTMLLinkElement/link-preload-validity-expected.txt
@@ -1,4 +1,4 @@
-CONSOLE WARNING: line 10: <link rel=preload> must have a valid `as` value
+CONSOLE DEBUG: line 10: Preload triggered for prefetch.wut.com.test/1.gif
 CONSOLE WARNING: line 11: <link rel=preload> has an invalid `href` value
 CONSOLE WARNING: line 12: <link rel=preload> has an invalid `href` value
 CONSOLE WARNING: line 13: <link rel=preload> has an invalid `href` value
diff --git a/third_party/WebKit/LayoutTests/fast/dom/XMLSerializer.html b/third_party/WebKit/LayoutTests/fast/dom/XMLSerializer.html
index 1e274a5..d41cb53 100644
--- a/third_party/WebKit/LayoutTests/fast/dom/XMLSerializer.html
+++ b/third_party/WebKit/LayoutTests/fast/dom/XMLSerializer.html
@@ -44,6 +44,10 @@
 test(function() {
     var attr = child2.getAttributeNode('attr');
     assert_equals(serializer.serializeToString(attr), 'an attribute');
+
+    var element = doc.createElement('foo');
+    element.setAttribute('attr1', ' abc\ndef\tghi\r');
+    assert_equals(serializer.serializeToString(element), '<foo attr1=" abc&#10;def&#9;ghi&#13;"/>');
 }, 'Check Attr serializiation.');
 </script>
 </body>
diff --git a/third_party/WebKit/LayoutTests/fast/files/url-null-expected.txt b/third_party/WebKit/LayoutTests/fast/files/url-null-expected.txt
index b55d73a9..681eb428 100644
--- a/third_party/WebKit/LayoutTests/fast/files/url-null-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/files/url-null-expected.txt
@@ -1,9 +1,11 @@
-Test URL methods with null arguments.
+Test URL methods with null and undefined arguments.
 
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
 
-PASS URL.createObjectURL(null) is null
-URL.revokeObjectURL(null)
+PASS URL.createObjectURL(null) threw exception TypeError: Failed to execute 'createObjectURL' on 'URL': No function was found that matched the signature provided..
+PASS URL.createObjectURL(undefined) threw exception TypeError: Failed to execute 'createObjectURL' on 'URL': No function was found that matched the signature provided..
+PASS URL.revokeObjectURL(null) did not throw exception.
+PASS URL.revokeObjectURL(undefined) did not throw exception.
 PASS successfullyParsed is true
 
 TEST COMPLETE
diff --git a/third_party/WebKit/LayoutTests/fast/files/url-null.html b/third_party/WebKit/LayoutTests/fast/files/url-null.html
index 744a833..95dd3e06 100644
--- a/third_party/WebKit/LayoutTests/fast/files/url-null.html
+++ b/third_party/WebKit/LayoutTests/fast/files/url-null.html
@@ -7,10 +7,12 @@
     <div id="description"></div>
     <div id="console"></div>
 <script>
-description("Test URL methods with null arguments.");
+description("Test URL methods with null and undefined arguments.");
 
-shouldBe("URL.createObjectURL(null)", "null");
-evalAndLog("URL.revokeObjectURL(null)");
+shouldThrow("URL.createObjectURL(null)");
+shouldThrow("URL.createObjectURL(undefined)");
+shouldNotThrow("URL.revokeObjectURL(null)");
+shouldNotThrow("URL.revokeObjectURL(undefined)");
 var successfullyParsed = true;
 
 </script>
diff --git a/third_party/WebKit/LayoutTests/fast/forms/select/option-defaultselected-expected.txt b/third_party/WebKit/LayoutTests/fast/forms/select/option-defaultselected-expected.txt
index b9fd965..c24bb4b 100644
--- a/third_party/WebKit/LayoutTests/fast/forms/select/option-defaultselected-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/forms/select/option-defaultselected-expected.txt
@@ -13,7 +13,7 @@
 PASS selectionMap(select1) is "100"
 PASS select1[2].defaultSelected = true; selectionMap(select1) is "001"
 PASS select1[1].defaultSelected = true; selectionMap(select1) is "010"
-PASS select1[1].defaultSelected = false; selectionMap(select1) is "010"
+PASS select1[1].defaultSelected = false; selectionMap(select1) is "100"
 PASS select1[2].selected = true; selectionMap(select1) is "001"
 PASS successfullyParsed is true
 
diff --git a/third_party/WebKit/LayoutTests/fast/forms/select/option-defaultselected.html b/third_party/WebKit/LayoutTests/fast/forms/select/option-defaultselected.html
index 4557bbc..91f72a32 100644
--- a/third_party/WebKit/LayoutTests/fast/forms/select/option-defaultselected.html
+++ b/third_party/WebKit/LayoutTests/fast/forms/select/option-defaultselected.html
@@ -27,7 +27,7 @@
 
 shouldBeEqualToString('select1[2].defaultSelected = true; selectionMap(select1)', '001');
 shouldBeEqualToString('select1[1].defaultSelected = true; selectionMap(select1)', '010');
-shouldBeEqualToString('select1[1].defaultSelected = false; selectionMap(select1)', '010');
+shouldBeEqualToString('select1[1].defaultSelected = false; selectionMap(select1)', '100');
 shouldBeEqualToString('select1[2].selected = true; selectionMap(select1)', '001');
 </script>
 </body>
diff --git a/third_party/WebKit/LayoutTests/fast/input/placeholder-wrongly-placed-if-too-tall-expected.txt b/third_party/WebKit/LayoutTests/fast/input/placeholder-wrongly-placed-if-too-tall-expected.txt
new file mode 100644
index 0000000..43431cf
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/input/placeholder-wrongly-placed-if-too-tall-expected.txt
@@ -0,0 +1,7 @@
+Both inputs should be of the same size and the placeholder should be at the same place.
+PASS rect0.top is rect1.top
+PASS rect0.height is rect1.height
+PASS successfullyParsed is true
+
+TEST COMPLETE
+ 
diff --git a/third_party/WebKit/LayoutTests/fast/input/placeholder-wrongly-placed-if-too-tall.html b/third_party/WebKit/LayoutTests/fast/input/placeholder-wrongly-placed-if-too-tall.html
new file mode 100644
index 0000000..523f5691
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/input/placeholder-wrongly-placed-if-too-tall.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<style>
+input {
+    height: 26px;
+    line-height: 29px;
+    padding: 0 5px;
+    border: none;
+    border-bottom: 1px solid #888;
+    outline: none;
+}
+</style>
+<div>Both inputs should be of the same size and the placeholder should be at the same place.</div>
+<div id="console"></div>
+<input type="text" placeholder="placeholder">
+<input type="text" placeholder="placeholder">
+<script>
+window.jsTestIsAsync = true;
+
+var inputs = document.getElementsByTagName("input");
+
+function checkInputs()
+{
+    rect0 = inputs[0].getBoundingClientRect();
+    rect1 = inputs[1].getBoundingClientRect();
+    shouldBe("rect0.top", "rect1.top");
+    shouldBe("rect0.height", "rect1.height");
+
+    finishJSTest();
+}
+
+inputs[1].focus();
+// Forcing a layout in this frame makes the issue disappear.
+window.requestAnimationFrame(checkInputs);
+</script>
+<script src="../../resources/js-test.js"></script>
diff --git a/third_party/WebKit/LayoutTests/fast/media/mq-width-on-zoom-expected.txt b/third_party/WebKit/LayoutTests/fast/media/mq-width-on-zoom-expected.txt
index 080182be..43809869 100644
--- a/third_party/WebKit/LayoutTests/fast/media/mq-width-on-zoom-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/media/mq-width-on-zoom-expected.txt
@@ -1,18 +1,33 @@
-PASS window.matchMedia('(width: 960px)').matches is true
-PASS window.matchMedia('(width: 1152px)').matches is true
-PASS window.matchMedia('(width: 1382px)').matches is true
-PASS window.matchMedia('(width: 1658px)').matches is true
-PASS window.matchMedia('(width: 1990px)').matches is true
-PASS window.matchMedia('(width: 1658px)').matches is true
-PASS window.matchMedia('(width: 1382px)').matches is true
-PASS window.matchMedia('(width: 1152px)').matches is true
-PASS window.matchMedia('(width: 960px)').matches is true
-PASS window.matchMedia('(width: 800px)').matches is true
-PASS window.matchMedia('(width: 667px)').matches is true
-PASS window.matchMedia('(width: 555px)').matches is true
-PASS window.matchMedia('(width: 463px)').matches is true
-PASS window.matchMedia('(width: 386px)').matches is true
-PASS window.matchMedia('(width: 321px)').matches is true
+PASS window.matchMedia('(min-width: 959px)').matches is true
+PASS window.matchMedia('(max-width: 961px)').matches is true
+PASS window.matchMedia('(min-width: 1151px)').matches is true
+PASS window.matchMedia('(max-width: 1153px)').matches is true
+PASS window.matchMedia('(min-width: 1381px)').matches is true
+PASS window.matchMedia('(max-width: 1383px)').matches is true
+PASS window.matchMedia('(min-width: 1657px)').matches is true
+PASS window.matchMedia('(max-width: 1659px)').matches is true
+PASS window.matchMedia('(min-width: 1989px)').matches is true
+PASS window.matchMedia('(max-width: 1991px)').matches is true
+PASS window.matchMedia('(min-width: 1657px)').matches is true
+PASS window.matchMedia('(max-width: 1659px)').matches is true
+PASS window.matchMedia('(min-width: 1381px)').matches is true
+PASS window.matchMedia('(max-width: 1383px)').matches is true
+PASS window.matchMedia('(min-width: 1151px)').matches is true
+PASS window.matchMedia('(max-width: 1153px)').matches is true
+PASS window.matchMedia('(min-width: 959px)').matches is true
+PASS window.matchMedia('(max-width: 961px)').matches is true
+PASS window.matchMedia('(min-width: 799px)').matches is true
+PASS window.matchMedia('(max-width: 801px)').matches is true
+PASS window.matchMedia('(min-width: 666px)').matches is true
+PASS window.matchMedia('(max-width: 668px)').matches is true
+PASS window.matchMedia('(min-width: 554px)').matches is true
+PASS window.matchMedia('(max-width: 556px)').matches is true
+PASS window.matchMedia('(min-width: 462px)').matches is true
+PASS window.matchMedia('(max-width: 464px)').matches is true
+PASS window.matchMedia('(min-width: 385px)').matches is true
+PASS window.matchMedia('(max-width: 387px)').matches is true
+PASS window.matchMedia('(min-width: 320px)').matches is true
+PASS window.matchMedia('(max-width: 322px)').matches is true
 PASS successfullyParsed is true
 
 TEST COMPLETE
diff --git a/third_party/WebKit/LayoutTests/fast/media/mq-width-on-zoom.html b/third_party/WebKit/LayoutTests/fast/media/mq-width-on-zoom.html
index 6456ca5a..ad4f5e1 100644
--- a/third_party/WebKit/LayoutTests/fast/media/mq-width-on-zoom.html
+++ b/third_party/WebKit/LayoutTests/fast/media/mq-width-on-zoom.html
@@ -11,24 +11,11 @@
             // eventSender.zoomPageOut/In zooms with a fixed factor of 1.2 instead
             // of the zoom levels of the actual browser.
 
-            function printMatch(match) {
-                return (match > 0) ? "matches " + match + "px." : "doesn't match tested values.";
-            }
-
             function test() {
-                shouldBeTrue("window.matchMedia('(width: " + window.innerWidth + "px)').matches");
-                if (window.matchMedia("(width: " + window.innerWidth + "px)").matches)
-                    return;
-
-                var matches = 0
-                for (var j = 0; j < window.innerWidth + 100; j++) {
-                    if (window.matchMedia("(width: " + j + "px)").matches) {
-                        matches = j;
-                        break;
-                    }
-                }
-
-                debug("window.innerWidth is " + window.innerWidth + "px, but width MQ feature " + printMatch(j));
+                var minWidth = window.innerWidth - 1;
+                var maxWidth = window.innerWidth + 1;
+                shouldBeTrue("window.matchMedia('(min-width: " + minWidth + "px)').matches");
+                shouldBeTrue("window.matchMedia('(max-width: " + maxWidth + "px)').matches");
             }
 
             if (window.eventSender) {
diff --git a/third_party/WebKit/LayoutTests/fast/mediastream/RTCPeerConnection-createOffer-expected.txt b/third_party/WebKit/LayoutTests/fast/mediastream/RTCPeerConnection-createOffer-expected.txt
index 84dc3a14..5fac49e 100644
--- a/third_party/WebKit/LayoutTests/fast/mediastream/RTCPeerConnection-createOffer-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/mediastream/RTCPeerConnection-createOffer-expected.txt
@@ -7,6 +7,11 @@
 PASS sessionDescription.type is "offer"
 PASS requestFailed was called.
 PASS errorReason is "TEST_ERROR"
+PASS pc.createOffer(dummy, dummy); did not throw exception.
+PASS pc.createOffer(dummy, dummy, {}); did not throw exception.
+PASS pc.createOffer(dummy, dummy, {voiceActivityDetection:false}); did not throw exception.
+PASS pc.createOffer(dummy, dummy, {iceRestart:true}); did not throw exception.
+PASS pc.createOffer(dummy, dummy, {voiceActivityDetection:false, iceRestart:true}); did not throw exception.
 PASS pc.createOffer(dummy, dummy, {offerToReceiveVideo:-1, offerToReceiveAudio:0}); threw exception TypeError: Failed to execute 'createOffer' on 'RTCPeerConnection': Invalid offerToReceiveVideo.
 PASS pc.createOffer(dummy, dummy, {offerToReceiveVideo:0, offerToReceiveAudio:-1}); threw exception TypeError: Failed to execute 'createOffer' on 'RTCPeerConnection': Invalid offerToReceiveAudio.
 PASS pc.createOffer(dummy, dummy, {offerToReceiveVideo:1, offerToReceiveAudio:0, voiceActivityDetection:false, iceRestart:true}); did not throw exception.
diff --git a/third_party/WebKit/LayoutTests/fast/mediastream/RTCPeerConnection-createOffer.html b/third_party/WebKit/LayoutTests/fast/mediastream/RTCPeerConnection-createOffer.html
index 55e310e9..38258b1 100644
--- a/third_party/WebKit/LayoutTests/fast/mediastream/RTCPeerConnection-createOffer.html
+++ b/third_party/WebKit/LayoutTests/fast/mediastream/RTCPeerConnection-createOffer.html
@@ -7,6 +7,10 @@
 <script>
 description("Tests RTCPeerConnection createOffer.");
 
+// Note: createOffer() calls in the test runner are successful if the
+// voiceActivityDetection and iceRestart options are passed with a value of true.
+// In all other cases, createOffer() fails in the test runner.
+
 var pc = null;
 
 function dummy() {}
@@ -18,6 +22,13 @@
     errorReason = reason;
     shouldBe('errorReason', '"TEST_ERROR"');
 
+    shouldNotThrow("pc.createOffer(dummy, dummy);");
+    shouldNotThrow("pc.createOffer(dummy, dummy, {});");
+    shouldNotThrow("pc.createOffer(dummy, dummy, {voiceActivityDetection:false});");
+    shouldNotThrow("pc.createOffer(dummy, dummy, {iceRestart:true});");
+    shouldNotThrow("pc.createOffer(dummy, dummy, {voiceActivityDetection:false, iceRestart:true});");
+
+    // Deprecated.
     shouldThrow("pc.createOffer(dummy, dummy, {offerToReceiveVideo:-1, offerToReceiveAudio:0});");
     shouldThrow("pc.createOffer(dummy, dummy, {offerToReceiveVideo:0, offerToReceiveAudio:-1});");
     shouldNotThrow("pc.createOffer(dummy, dummy, {offerToReceiveVideo:1, offerToReceiveAudio:0, voiceActivityDetection:false, iceRestart:true});");
@@ -44,11 +55,11 @@
     sessionDescription = sd;
     shouldBe('sessionDescription.type', '"offer"');
 
-    pc.createOffer(requestSucceeded2, requestFailed2, {mandatory:{"succeed":false}});
+    pc.createOffer(requestSucceeded2, requestFailed2);
 }
 
-pc = new webkitRTCPeerConnection(null, null);
-pc.createOffer(requestSucceeded1, requestFailed1, {mandatory:{"succeed":true}});
+pc = new webkitRTCPeerConnection(null);
+pc.createOffer(requestSucceeded1, requestFailed1, {voiceActivityDetection:true, iceRestart:true});
 
 window.jsTestIsAsync = true;
 window.successfullyParsed = true;
diff --git a/third_party/WebKit/LayoutTests/fast/mediastream/RTCPeerConnection-expected.txt b/third_party/WebKit/LayoutTests/fast/mediastream/RTCPeerConnection-expected.txt
index 123515ea..e5b6598b8 100644
--- a/third_party/WebKit/LayoutTests/fast/mediastream/RTCPeerConnection-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/mediastream/RTCPeerConnection-expected.txt
@@ -4,35 +4,32 @@
 
 
 PASS new webkitRTCPeerConnection(null); did not throw exception.
-PASS new webkitRTCPeerConnection(null, null); did not throw exception.
 PASS new webkitRTCPeerConnection(undefined); did not throw exception.
-PASS new webkitRTCPeerConnection(undefined, undefined); did not throw exception.
 PASS new webkitRTCPeerConnection(); threw exception TypeError: Failed to construct 'RTCPeerConnection': 1 argument required, but only 0 present..
 PASS new webkitRTCPeerConnection(''); threw exception TypeError: Failed to construct 'RTCPeerConnection': parameter 1 ('rtcConfiguration') is not an object..
-PASS new webkitRTCPeerConnection(null, ''); threw exception TypeError: Failed to construct 'RTCPeerConnection': parameter 2 ('mediaConstraints') is not an object..
-PASS new webkitRTCPeerConnection({iceServers:[]}, null); did not throw exception.
-PASS new webkitRTCPeerConnection({iceServers:[{url:'stun:foo.com'}]}, null); did not throw exception.
-PASS new webkitRTCPeerConnection({iceServers:[{url:'turn:foo.com', credential:'x'}]}, null); did not throw exception.
-PASS new webkitRTCPeerConnection({iceServers:[{url:'turn:foo.com', credential:'x'},{url:'stun:bar.com'}]}, null); did not throw exception.
-PASS new webkitRTCPeerConnection({iceServers:[{urls:'stun:foo.com'}]}, null); did not throw exception.
-PASS new webkitRTCPeerConnection({iceServers:[{urls:['stun:foo.com', 'turn:foo.com']}]}, null); did not throw exception.
-PASS new webkitRTCPeerConnection({fooServers:[]}, null); threw exception TypeError: Failed to construct 'RTCPeerConnection': Malformed RTCConfiguration.
-PASS new webkitRTCPeerConnection({iceServers:true}, null); threw exception TypeError: Failed to construct 'RTCPeerConnection': Malformed RTCConfiguration.
-PASS new webkitRTCPeerConnection({iceServers:[1, 2, 3]}, null); threw exception TypeError: Failed to construct 'RTCPeerConnection': Malformed RTCIceServer.
-PASS new webkitRTCPeerConnection({iceServers:[{}]}, null); threw exception TypeError: Failed to construct 'RTCPeerConnection': Malformed RTCIceServer.
-PASS new webkitRTCPeerConnection({iceServers:[{url:'foo'}]}, null); threw exception TypeError: Failed to construct 'RTCPeerConnection': Malformed URL.
-PASS new webkitRTCPeerConnection({iceServers:[{urls:[1, 'turn:foo.com']}]}, null); threw exception TypeError: Failed to construct 'RTCPeerConnection': Malformed URL.
-PASS new webkitRTCPeerConnection({iceServers:[], iceTransports:'none'}, null); did not throw exception.
-PASS new webkitRTCPeerConnection({iceServers:[], iceTransports:'relay'}, null); did not throw exception.
-PASS new webkitRTCPeerConnection({iceServers:[], iceTransports:'all'}, null); did not throw exception.
-PASS new webkitRTCPeerConnection({iceServers:[], iceTransports:'foo'}, null); threw exception TypeError: Failed to construct 'RTCPeerConnection': Malformed RTCIceTransports.
-PASS new webkitRTCPeerConnection({iceServers:[], bundlePolicy:'balanced'}, null); did not throw exception.
-PASS new webkitRTCPeerConnection({iceServers:[], bundlePolicy:'max-bundle'}, null); did not throw exception.
-PASS new webkitRTCPeerConnection({iceServers:[], bundlePolicy:'max-compat'}, null); did not throw exception.
-PASS new webkitRTCPeerConnection({iceServers:[], bundlePolicy:'foo'}, null); threw exception TypeError: Failed to construct 'RTCPeerConnection': Malformed RTCBundlePolicy.
-PASS new webkitRTCPeerConnection({iceServers:[], rtcpMuxPolicy:'negotiate'}, null); did not throw exception.
-PASS new webkitRTCPeerConnection({iceServers:[], rtcpMuxPolicy:'require'}, null); did not throw exception.
-PASS new webkitRTCPeerConnection({iceServers:[], rtcpMuxPolicy:'foo'}, null); threw exception TypeError: Failed to construct 'RTCPeerConnection': Malformed RTCRtcpMuxPolicy.
+PASS new webkitRTCPeerConnection({iceServers:[]}); did not throw exception.
+PASS new webkitRTCPeerConnection({iceServers:[{url:'stun:foo.com'}]}); did not throw exception.
+PASS new webkitRTCPeerConnection({iceServers:[{url:'turn:foo.com', credential:'x'}]}); did not throw exception.
+PASS new webkitRTCPeerConnection({iceServers:[{url:'turn:foo.com', credential:'x'},{url:'stun:bar.com'}]}); did not throw exception.
+PASS new webkitRTCPeerConnection({iceServers:[{urls:'stun:foo.com'}]}); did not throw exception.
+PASS new webkitRTCPeerConnection({iceServers:[{urls:['stun:foo.com', 'turn:foo.com']}]}); did not throw exception.
+PASS new webkitRTCPeerConnection({fooServers:[]}); threw exception TypeError: Failed to construct 'RTCPeerConnection': Malformed RTCConfiguration.
+PASS new webkitRTCPeerConnection({iceServers:true}); threw exception TypeError: Failed to construct 'RTCPeerConnection': Malformed RTCConfiguration.
+PASS new webkitRTCPeerConnection({iceServers:[1, 2, 3]}); threw exception TypeError: Failed to construct 'RTCPeerConnection': Malformed RTCIceServer.
+PASS new webkitRTCPeerConnection({iceServers:[{}]}); threw exception TypeError: Failed to construct 'RTCPeerConnection': Malformed RTCIceServer.
+PASS new webkitRTCPeerConnection({iceServers:[{url:'foo'}]}); threw exception TypeError: Failed to construct 'RTCPeerConnection': Malformed URL.
+PASS new webkitRTCPeerConnection({iceServers:[{urls:[1, 'turn:foo.com']}]}); threw exception TypeError: Failed to construct 'RTCPeerConnection': Malformed URL.
+PASS new webkitRTCPeerConnection({iceServers:[], iceTransports:'none'}); did not throw exception.
+PASS new webkitRTCPeerConnection({iceServers:[], iceTransports:'relay'}); did not throw exception.
+PASS new webkitRTCPeerConnection({iceServers:[], iceTransports:'all'}); did not throw exception.
+PASS new webkitRTCPeerConnection({iceServers:[], iceTransports:'foo'}); threw exception TypeError: Failed to construct 'RTCPeerConnection': Malformed RTCIceTransports.
+PASS new webkitRTCPeerConnection({iceServers:[], bundlePolicy:'balanced'}); did not throw exception.
+PASS new webkitRTCPeerConnection({iceServers:[], bundlePolicy:'max-bundle'}); did not throw exception.
+PASS new webkitRTCPeerConnection({iceServers:[], bundlePolicy:'max-compat'}); did not throw exception.
+PASS new webkitRTCPeerConnection({iceServers:[], bundlePolicy:'foo'}); threw exception TypeError: Failed to construct 'RTCPeerConnection': Malformed RTCBundlePolicy.
+PASS new webkitRTCPeerConnection({iceServers:[], rtcpMuxPolicy:'negotiate'}); did not throw exception.
+PASS new webkitRTCPeerConnection({iceServers:[], rtcpMuxPolicy:'require'}); did not throw exception.
+PASS new webkitRTCPeerConnection({iceServers:[], rtcpMuxPolicy:'foo'}); threw exception TypeError: Failed to construct 'RTCPeerConnection': Malformed RTCRtcpMuxPolicy.
 PASS new webkitRTCPeerConnection(null, {mandatory:{valid_and_supported_1:1}}); did not throw exception.
 PASS new webkitRTCPeerConnection(null, {mandatory:{valid_and_supported_1:1, valid_and_supported_2:1}}); did not throw exception.
 PASS new webkitRTCPeerConnection(null, {optional:[{valid_and_supported_1:0}]}); did not throw exception.
@@ -48,10 +45,10 @@
 PASS new webkitRTCPeerConnection(null, {valid_and_supported_1:1}); threw exception TypeError: Failed to construct 'RTCPeerConnection': Malformed constraints object..
 PASS new webkitRTCPeerConnection(null, {valid_but_unsupported_1:1}); threw exception TypeError: Failed to construct 'RTCPeerConnection': Malformed constraints object..
 PASS new webkitRTCPeerConnection(null, {valid_and_supported_2:1, mandatory:{valid_and_supported_1:1}}); threw exception TypeError: Failed to construct 'RTCPeerConnection': Malformed constraints object..
-PASS new webkitRTCPeerConnection({iceServers:[], certificates:null}, null); did not throw exception.
-PASS new webkitRTCPeerConnection({iceServers:[], certificates:[]}, null); did not throw exception.
-PASS new webkitRTCPeerConnection({iceServers:[], certificates:[null]}, null); threw exception TypeError: Failed to construct 'RTCPeerConnection': Malformed sequence<RTCCertificate>.
-PASS new webkitRTCPeerConnection({iceServers:[], certificates:[1337]}, null); threw exception TypeError: Failed to construct 'RTCPeerConnection': Malformed sequence<RTCCertificate>.
+PASS new webkitRTCPeerConnection({iceServers:[], certificates:null}); did not throw exception.
+PASS new webkitRTCPeerConnection({iceServers:[], certificates:[]}); did not throw exception.
+PASS new webkitRTCPeerConnection({iceServers:[], certificates:[null]}); threw exception TypeError: Failed to construct 'RTCPeerConnection': Malformed sequence<RTCCertificate>.
+PASS new webkitRTCPeerConnection({iceServers:[], certificates:[1337]}); threw exception TypeError: Failed to construct 'RTCPeerConnection': Malformed sequence<RTCCertificate>.
 PASS new webkitRTCPeerConnection({iceServers:[], certificates:[certRSA]}, null); did not throw exception.
 PASS new webkitRTCPeerConnection({iceServers:[], certificates:[certECDSA]}, null); did not throw exception.
 PASS successfullyParsed is true
diff --git a/third_party/WebKit/LayoutTests/fast/mediastream/RTCPeerConnection.html b/third_party/WebKit/LayoutTests/fast/mediastream/RTCPeerConnection.html
index 0026c14..13da900 100644
--- a/third_party/WebKit/LayoutTests/fast/mediastream/RTCPeerConnection.html
+++ b/third_party/WebKit/LayoutTests/fast/mediastream/RTCPeerConnection.html
@@ -8,41 +8,39 @@
 description("Tests the RTCPeerConnection constructor.");
 
 shouldNotThrow("new webkitRTCPeerConnection(null);");
-shouldNotThrow("new webkitRTCPeerConnection(null, null);");
 shouldNotThrow("new webkitRTCPeerConnection(undefined);");
-shouldNotThrow("new webkitRTCPeerConnection(undefined, undefined);");
 shouldThrow("new webkitRTCPeerConnection();");
 shouldThrow("new webkitRTCPeerConnection('');");
-shouldThrow("new webkitRTCPeerConnection(null, '');");
 
-shouldNotThrow("new webkitRTCPeerConnection({iceServers:[]}, null);");
-shouldNotThrow("new webkitRTCPeerConnection({iceServers:[{url:'stun:foo.com'}]}, null);");
-shouldNotThrow("new webkitRTCPeerConnection({iceServers:[{url:'turn:foo.com', credential:'x'}]}, null);");
-shouldNotThrow("new webkitRTCPeerConnection({iceServers:[{url:'turn:foo.com', credential:'x'},{url:'stun:bar.com'}]}, null);");
-shouldNotThrow("new webkitRTCPeerConnection({iceServers:[{urls:'stun:foo.com'}]}, null);");
-shouldNotThrow("new webkitRTCPeerConnection({iceServers:[{urls:['stun:foo.com', 'turn:foo.com']}]}, null);");
+shouldNotThrow("new webkitRTCPeerConnection({iceServers:[]});");
+shouldNotThrow("new webkitRTCPeerConnection({iceServers:[{url:'stun:foo.com'}]});");
+shouldNotThrow("new webkitRTCPeerConnection({iceServers:[{url:'turn:foo.com', credential:'x'}]});");
+shouldNotThrow("new webkitRTCPeerConnection({iceServers:[{url:'turn:foo.com', credential:'x'},{url:'stun:bar.com'}]});");
+shouldNotThrow("new webkitRTCPeerConnection({iceServers:[{urls:'stun:foo.com'}]});");
+shouldNotThrow("new webkitRTCPeerConnection({iceServers:[{urls:['stun:foo.com', 'turn:foo.com']}]});");
 
-shouldThrow("new webkitRTCPeerConnection({fooServers:[]}, null);");
-shouldThrow("new webkitRTCPeerConnection({iceServers:true}, null);");
-shouldThrow("new webkitRTCPeerConnection({iceServers:[1, 2, 3]}, null);");
-shouldThrow("new webkitRTCPeerConnection({iceServers:[{}]}, null);");
-shouldThrow("new webkitRTCPeerConnection({iceServers:[{url:'foo'}]}, null);");
-shouldThrow("new webkitRTCPeerConnection({iceServers:[{urls:[1, 'turn:foo.com']}]}, null);");
+shouldThrow("new webkitRTCPeerConnection({fooServers:[]});");
+shouldThrow("new webkitRTCPeerConnection({iceServers:true});");
+shouldThrow("new webkitRTCPeerConnection({iceServers:[1, 2, 3]});");
+shouldThrow("new webkitRTCPeerConnection({iceServers:[{}]});");
+shouldThrow("new webkitRTCPeerConnection({iceServers:[{url:'foo'}]});");
+shouldThrow("new webkitRTCPeerConnection({iceServers:[{urls:[1, 'turn:foo.com']}]});");
 
-shouldNotThrow("new webkitRTCPeerConnection({iceServers:[], iceTransports:'none'}, null);");
-shouldNotThrow("new webkitRTCPeerConnection({iceServers:[], iceTransports:'relay'}, null);");
-shouldNotThrow("new webkitRTCPeerConnection({iceServers:[], iceTransports:'all'}, null);");
-shouldThrow("new webkitRTCPeerConnection({iceServers:[], iceTransports:'foo'}, null);");
+shouldNotThrow("new webkitRTCPeerConnection({iceServers:[], iceTransports:'none'});");
+shouldNotThrow("new webkitRTCPeerConnection({iceServers:[], iceTransports:'relay'});");
+shouldNotThrow("new webkitRTCPeerConnection({iceServers:[], iceTransports:'all'});");
+shouldThrow("new webkitRTCPeerConnection({iceServers:[], iceTransports:'foo'});");
 
-shouldNotThrow("new webkitRTCPeerConnection({iceServers:[], bundlePolicy:'balanced'}, null);");
-shouldNotThrow("new webkitRTCPeerConnection({iceServers:[], bundlePolicy:'max-bundle'}, null);");
-shouldNotThrow("new webkitRTCPeerConnection({iceServers:[], bundlePolicy:'max-compat'}, null);");
-shouldThrow("new webkitRTCPeerConnection({iceServers:[], bundlePolicy:'foo'}, null);");
+shouldNotThrow("new webkitRTCPeerConnection({iceServers:[], bundlePolicy:'balanced'});");
+shouldNotThrow("new webkitRTCPeerConnection({iceServers:[], bundlePolicy:'max-bundle'});");
+shouldNotThrow("new webkitRTCPeerConnection({iceServers:[], bundlePolicy:'max-compat'});");
+shouldThrow("new webkitRTCPeerConnection({iceServers:[], bundlePolicy:'foo'});");
 
-shouldNotThrow("new webkitRTCPeerConnection({iceServers:[], rtcpMuxPolicy:'negotiate'}, null);");
-shouldNotThrow("new webkitRTCPeerConnection({iceServers:[], rtcpMuxPolicy:'require'}, null);");
-shouldThrow("new webkitRTCPeerConnection({iceServers:[], rtcpMuxPolicy:'foo'}, null);");
+shouldNotThrow("new webkitRTCPeerConnection({iceServers:[], rtcpMuxPolicy:'negotiate'});");
+shouldNotThrow("new webkitRTCPeerConnection({iceServers:[], rtcpMuxPolicy:'require'});");
+shouldThrow("new webkitRTCPeerConnection({iceServers:[], rtcpMuxPolicy:'foo'});");
 
+// Deprecated.
 shouldNotThrow("new webkitRTCPeerConnection(null, {mandatory:{valid_and_supported_1:1}});");
 shouldNotThrow("new webkitRTCPeerConnection(null, {mandatory:{valid_and_supported_1:1, valid_and_supported_2:1}});");
 shouldNotThrow("new webkitRTCPeerConnection(null, {optional:[{valid_and_supported_1:0}]});");
@@ -60,10 +58,10 @@
 shouldThrow("new webkitRTCPeerConnection(null, {valid_and_supported_2:1, mandatory:{valid_and_supported_1:1}});");
 
 // Construct with certificates.
-shouldNotThrow("new webkitRTCPeerConnection({iceServers:[], certificates:null}, null);");
-shouldNotThrow("new webkitRTCPeerConnection({iceServers:[], certificates:[]}, null);");
-shouldThrow("new webkitRTCPeerConnection({iceServers:[], certificates:[null]}, null);");
-shouldThrow("new webkitRTCPeerConnection({iceServers:[], certificates:[1337]}, null);");
+shouldNotThrow("new webkitRTCPeerConnection({iceServers:[], certificates:null});");
+shouldNotThrow("new webkitRTCPeerConnection({iceServers:[], certificates:[]});");
+shouldThrow("new webkitRTCPeerConnection({iceServers:[], certificates:[null]});");
+shouldThrow("new webkitRTCPeerConnection({iceServers:[], certificates:[1337]});");
 // Global certificate variables so that the "should..." methods can evaluate them.
 var certRSA = null;
 var certECDSA = null;
diff --git a/third_party/WebKit/LayoutTests/fast/multicol/span/in-nested-multicol-with-hard-breaks-expected.html b/third_party/WebKit/LayoutTests/fast/multicol/span/in-nested-multicol-with-hard-breaks-expected.html
new file mode 100644
index 0000000..33f4c7c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/multicol/span/in-nested-multicol-with-hard-breaks-expected.html
@@ -0,0 +1,4 @@
+<!DOCTYPE html>
+<p>Test that forced outer fragmentainer breaks work inside spanners in nested multicol.</p>
+<p>There should be a blue square below.</p>
+<div style="width:60px; height:60px; background:blue;"></div>
diff --git a/third_party/WebKit/LayoutTests/fast/multicol/span/in-nested-multicol-with-hard-breaks.html b/third_party/WebKit/LayoutTests/fast/multicol/span/in-nested-multicol-with-hard-breaks.html
new file mode 100644
index 0000000..fe8f9ed
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/multicol/span/in-nested-multicol-with-hard-breaks.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<style>
+    .breakAfter { -webkit-column-break-after:always; }
+    .breakBefore { -webkit-column-break-before:always; }
+    .piece { background:blue; }
+</style>
+<p>Test that forced outer fragmentainer breaks work inside spanners in nested multicol.</p>
+<p>There should be a blue square below.</p>
+<div style="-webkit-columns:4; -webkit-column-gap:0; column-fill:auto; width:60px; line-height:30px; height:135px; overflow:hidden;">
+    <div style="-webkit-columns:2; -webkit-column-gap:0;">
+        <div style="-webkit-column-span:all;">
+            <div class="piece breakBefore"><br></div>
+            <div class="piece breakAfter"><br></div>
+            <div class="piece"><br></div>
+            <div class="piece"><br></div>
+            <div class="piece breakBefore"><br></div>
+            <div class="piece"><br></div>
+            <br>
+            <br>
+            <div class="piece breakBefore"><br></div>
+            <div class="piece breakAfter"><br></div>
+        </div>
+    </div>
+</div>
diff --git a/third_party/WebKit/LayoutTests/fast/multicol/span/in-nested-multicol-with-soft-breaks-inside-expected.html b/third_party/WebKit/LayoutTests/fast/multicol/span/in-nested-multicol-with-soft-breaks-inside-expected.html
new file mode 100644
index 0000000..a77955b2
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/multicol/span/in-nested-multicol-with-soft-breaks-inside-expected.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<style>
+    .line { clear:both; }
+    .fakeColumn { float:left; width:1em; }
+    .fakeSpan { float:left; width:2em; }
+    .first { color:green; }
+    .second { color:blue; }
+</style>
+<p>Test that a column-span:all in an inner multicol container breaks nicely within the outer
+    multicol container.</p>
+<p>There should be two lines with letters below, with large letter spacing. The first line should
+    have green letters. The second line should have blue letters.</p>
+<div style="font:16px/30px monospace;">
+    <div class="line first">
+        <div class="fakeColumn">C</div>
+        <div class="fakeColumn">A</div>
+        <div class="fakeSpan">N</div>
+        <div class="fakeSpan">I</div>
+        <div class="fakeColumn">B</div>
+        <div class="fakeColumn">E</div>
+    </div>
+    <div class="line second">
+        <div class="fakeSpan">M</div>
+        <div class="fakeSpan">R</div>
+        <div class="fakeColumn">B</div>
+        <div class="fakeColumn">E</div>
+        <div class="fakeColumn">E</div>
+        <div class="fakeColumn">R</div>
+    </div>
+</div>
diff --git a/third_party/WebKit/LayoutTests/fast/multicol/span/in-nested-multicol-with-soft-breaks-inside.html b/third_party/WebKit/LayoutTests/fast/multicol/span/in-nested-multicol-with-soft-breaks-inside.html
new file mode 100644
index 0000000..8886efd
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/multicol/span/in-nested-multicol-with-soft-breaks-inside.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<style>
+    .first { color:green; }
+    .second { color:blue; }
+</style>
+<p>Test that a column-span:all in an inner multicol container breaks nicely within the outer
+    multicol container.</p>
+<p>There should be two lines with letters below, with large letter spacing. The first line should
+    have green letters. The second line should have blue letters.</p>
+<div style="-webkit-columns:4; -webkit-column-gap:0; column-fill:auto; width:8em; height:70px; font:16px/30px monospace;">
+    <div style="-webkit-columns:2; -webkit-column-gap:0;">
+        <span class="first">C<br></span>
+        <span class="first">A<br></span>
+        <div style="-webkit-column-span:all;">
+            <span class="second">M<br></span>
+            <span class="first">N<br></span>
+            <span class="second">R<br></span>
+            <span class="first">I<br></span>
+        </div>
+        <span class="second">B<br></span>
+        <span class="second">E<br></span>
+        <span class="first">B<br></span>
+        <span class="second">E<br></span>
+        <span class="first">E<br></span>
+        <span class="second">R<br></span>
+    </div>
+</div>
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/compiler-script-mapping-expected.txt b/third_party/WebKit/LayoutTests/http/tests/inspector/compiler-script-mapping-expected.txt
index 6b5d734..899732c 100644
--- a/third_party/WebKit/LayoutTests/http/tests/inspector/compiler-script-mapping-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector/compiler-script-mapping-expected.txt
@@ -147,3 +147,9 @@
 0 === 0
 0 === 0
 
+Running: testNameClash
+example.js === example.js [sm]
+0 === 0
+9 === 9
+source line 0 has no mappings.
+
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/compiler-script-mapping.html b/third_party/WebKit/LayoutTests/http/tests/inspector/compiler-script-mapping.html
index 71999c1f..841bdc6 100644
--- a/third_party/WebKit/LayoutTests/http/tests/inspector/compiler-script-mapping.html
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector/compiler-script-mapping.html
@@ -87,7 +87,7 @@
                 "mappings":"AAASA,QAAAA,IAAG,CAACC,CAAD,CAAaC,CAAb,CACZ,CACI,MAAOD,EAAP,CAAoBC,CADxB,CAIA,IAAIC,OAAS;A",
                 "sources":["example.js"]
             };
-            var mapping = new WebInspector.SourceMap("source-map.json", mappingPayload);
+            var mapping = new WebInspector.SourceMap("compiled.js", "source-map.json", mappingPayload);
 
             checkMapping(0, 9, "example.js", 0, 9, mapping);
             checkMapping(0, 13, "example.js", 0, 13, mapping);
@@ -112,7 +112,7 @@
                 "mappings":"AAAA,C,CAAE;",
                 "sources":["example.js"]
             };
-            var mapping = new WebInspector.SourceMap("source-map.json", mappingPayload);
+            var mapping = new WebInspector.SourceMap("compiled.js", "source-map.json", mappingPayload);
             checkMapping(0, 0, "example.js", 0, 0, mapping);
             var entry = mapping.findEntry(0, 1);
             InspectorTest.assertTrue(!entry.sourceURL);
@@ -126,7 +126,7 @@
                 "mappings":"AAAA;;;CACA",
                 "sources":["example.js"]
             };
-            var mapping = new WebInspector.SourceMap("source-map.json", mappingPayload);
+            var mapping = new WebInspector.SourceMap("compiled.js", "source-map.json", mappingPayload);
             checkMapping(0, 0, "example.js", 0, 0, mapping);
             checkReverseMapping(3, 1, "example.js", 1, mapping);
             next();
@@ -149,7 +149,7 @@
                     }
                 }
             ]};
-            var mapping = new WebInspector.SourceMap("source-map.json", mappingPayload);
+            var mapping = new WebInspector.SourceMap("compiled.js", "source-map.json", mappingPayload);
             InspectorTest.assertEquals(2, mapping.sources().length);
             checkMapping(0, 0, "source1.js", 0, 0, mapping);
             checkMapping(0, 1, "source1.js", 2, 1, mapping);
@@ -458,11 +458,24 @@
                 "sources":["example.js"],
                 "sourceRoot":"/"
             };
-            var mapping = new WebInspector.SourceMap("source-map.json", mappingPayload);
+            var mapping = new WebInspector.SourceMap("compiled.js", "source-map.json", mappingPayload);
             checkMapping(0, 9, "/example.js", 0, 9, mapping);
             checkReverseMapping(0, 0, "/example.js", 0, mapping);
             next();
         },
+
+        function testNameClash(next)
+        {
+            var mappingPayload = {
+                "mappings":"AAASA,QAAAA,IAAG,CAACC,CAAD,CAAaC,CAAb,CACZ,CACI,MAAOD,EAAP,CAAoBC,CADxB,CAIA,IAAIC,OAAS;",
+                "sources":["example.js"],
+                "sourcesContent":["var i = 0;"]
+            };
+            var mapping = new WebInspector.SourceMap("example.js", "source-map.json",mappingPayload);
+            checkMapping(0, 9, "example.js", 0, 9, mapping);
+            checkReverseMapping(0, 0, "example.js", 0, mapping);
+            next();
+        }
     ]);
 };
 
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/debugger-test.js b/third_party/WebKit/LayoutTests/http/tests/inspector/debugger-test.js
index 5cca2aa8..b2992a5 100644
--- a/third_party/WebKit/LayoutTests/http/tests/inspector/debugger-test.js
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector/debugger-test.js
@@ -373,7 +373,7 @@
 
     function dumpNavigatorTreeElement(prefix, treeElement)
     {
-        InspectorTest.addResult(prefix + treeElement.titleText);
+        InspectorTest.addResult(prefix + treeElement.nodeTitle());
         var children = treeElement.children();
         for (var i = 0; i < children.length; ++i)
             dumpNavigatorTreeElement(prefix + "  ", children[i]);
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/filesystem/request-metadata-expected.txt b/third_party/WebKit/LayoutTests/http/tests/inspector/filesystem/request-metadata-expected.txt
deleted file mode 100644
index 28dbfa4..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/inspector/filesystem/request-metadata-expected.txt
+++ /dev/null
@@ -1,23 +0,0 @@
-Tests requestMetadata command.
-
-errorCode: 2
-metadata: (null)
-
-errorCode: 5
-metadata: (null)
-
-errorCode: 0
-metadata:
-  modificationTime: (exists)
-  size: 4
-
-errorCode: 0
-metadata:
-  modificationTime: (exists)
-  size: 0
-
-errorCode: 1
-metadata: (null)
-
-All tests have done.
-
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/filesystem/request-metadata.html b/third_party/WebKit/LayoutTests/http/tests/inspector/filesystem/request-metadata.html
deleted file mode 100644
index 95c6385..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/inspector/filesystem/request-metadata.html
+++ /dev/null
@@ -1,78 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<meta charset="UTF-8">
-<script src="../inspector-test.js"></script>
-<script src="filesystem-test.js"></script>
-<script>
-document.addEventListener("DOMContentLoaded", runTest);
-function test()
-{
-    var fileSystemModel = new WebInspector.FileSystemModel(WebInspector.targetManager.mainTarget());
-
-    var testStep = [
-        function()
-        {
-            InspectorTest.writeFile("/hoge", "fuga", testStep.shift());
-        },
-
-        function()
-        {
-            fileSystemModel.requestMetadata(new InspectorTest.MockEntry("InvalidURL"), testStep.shift());
-        },
-
-        function(errorCode, metadata)
-        {
-            InspectorTest.dumpMetadataRequestResult(errorCode, metadata);
-            fileSystemModel.requestMetadata(new InspectorTest.MockEntry("filesystem:http://127.0.0.1:8000/InvalidType"), testStep.shift());
-        },
-
-        function(errorCode, metadata)
-        {
-            InspectorTest.dumpMetadataRequestResult(errorCode, metadata);
-            fileSystemModel.requestMetadata(new InspectorTest.MockEntry("filesystem:http://127.0.0.1:8000/temporary/hoge"), testStep.shift());
-        },
-
-        function(errorCode, metadata)
-        {
-            InspectorTest.dumpMetadataRequestResult(errorCode, metadata);
-            InspectorTest.createDirectory("/piyo", testStep.shift());
-        },
-
-        function()
-        {
-            fileSystemModel.requestMetadata(new InspectorTest.MockEntry("filesystem:http://127.0.0.1:8000/temporary/piyo"), testStep.shift());
-        },
-
-        function(errorCode, metadata)
-        {
-            InspectorTest.dumpMetadataRequestResult(errorCode, metadata);
-            fileSystemModel.requestMetadata(new InspectorTest.MockEntry("filesystem:http://127.0.0.1:8000/temporary/foo"), testStep.shift());
-        },
-
-        function(errorCode, metadata)
-        {
-            InspectorTest.dumpMetadataRequestResult(errorCode, metadata);
-            fileSystemModel.requestMetadata(new InspectorTest.MockEntry("filesystem:http://example.com/temporary/bar"), testStep.shift());
-        },
-
-        function(errorCode)
-        {
-            InspectorTest.clearFileSystem(testStep.shift());
-        },
-
-        function()
-        {
-            InspectorTest.addResult("All tests have done.");
-            InspectorTest.completeTest();
-        }
-    ];
-
-    InspectorTest.clearFileSystem(testStep.shift());
-}
-</script>
-</head>
-<body>
-<p>Tests requestMetadata command.</p>
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/plugins/get-url-expected.txt b/third_party/WebKit/LayoutTests/http/tests/plugins/get-url-expected.txt
deleted file mode 100644
index 7beb442..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/plugins/get-url-expected.txt
+++ /dev/null
@@ -1 +0,0 @@
-This tests that NPN_GetURLNotify works as expected and does not ASSERT intermittently in debug builds. 
diff --git a/third_party/WebKit/LayoutTests/http/tests/plugins/get-url-notify-on-removal-expected.txt b/third_party/WebKit/LayoutTests/http/tests/plugins/get-url-notify-on-removal-expected.txt
deleted file mode 100644
index 113aa4c..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/plugins/get-url-notify-on-removal-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-ALERT: Request completed
-This tests that NPP_URLNotify gets called exactly once for canceled streams on plugin removal.
-SUCCESS
-
diff --git a/third_party/WebKit/LayoutTests/http/tests/plugins/get-url-notify-on-removal.html b/third_party/WebKit/LayoutTests/http/tests/plugins/get-url-notify-on-removal.html
deleted file mode 100644
index d2a01bd8..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/plugins/get-url-notify-on-removal.html
+++ /dev/null
@@ -1,40 +0,0 @@
-<html>
-<body>
-This tests that NPP_URLNotify gets called exactly once for canceled streams on plugin removal.
-<div id="result">FAILURE</div>
-<embed name="plg" type="application/x-webkit-test-netscape"></embed>
-<script>
-    var callbackRun = false;
-    function callback()
-    {
-        if (callbackRun) {
-            result.textContent = "FAILURE - callback run twice";
-            return;
-        }
-
-        callbackRun = true;
-        result.textContent = "SUCCESS";
-        // Force the plugin to spin a nested event loop.
-        alert("Request completed");
-        // Don't stop the test until a small delay, in case callback is called again.
-        setTimeout(notify, 50);
-    }
-    function notify()
-    {
-        if (window.testRunner)
-            testRunner.notifyDone();
-    }
-    if (window.testRunner) {
-        testRunner.dumpAsText();
-        testRunner.waitUntilDone();
-    }
-
-    plg.getURLNotify("resources/slow-resource.pl", null, "callback");
-    // Remove the plugin after a short delay (to give the resource time to
-    // propagate through the system to the browser).
-    setTimeout(function() {
-        plg.parentNode.removeChild(plg);
-    }, 50);
-</script>
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/plugins/get-url.html b/third_party/WebKit/LayoutTests/http/tests/plugins/get-url.html
deleted file mode 100644
index 7b0e0a28..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/plugins/get-url.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<html>
-<body>
-This tests that NPN_GetURLNotify works as expected and does not ASSERT intermittently in debug builds.
-<embed name="plg" type="application/x-webkit-test-netscape"></embed>
-<script>
-    function notify()
-    {
-        if (window.testRunner)
-            testRunner.notifyDone();
-    }
-    if (window.testRunner) {
-        testRunner.dumpAsText();
-        testRunner.waitUntilDone();
-    }
-
-    plg.getURLNotify("resources/load-me-1.txt", null, "notify");
-</script>
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/plugins/geturlnotify-from-npp-destroystream-expected.txt b/third_party/WebKit/LayoutTests/http/tests/plugins/geturlnotify-from-npp-destroystream-expected.txt
deleted file mode 100644
index 8076e599..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/plugins/geturlnotify-from-npp-destroystream-expected.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-This tests that a plugin that calls NPP_GetURLNotify from its NPP_DestroyStream during teardown will not cause a crash.
-SUCCESS! Did not crash!
diff --git a/third_party/WebKit/LayoutTests/http/tests/plugins/geturlnotify-from-npp-destroystream.html b/third_party/WebKit/LayoutTests/http/tests/plugins/geturlnotify-from-npp-destroystream.html
deleted file mode 100644
index e2f6dc9..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/plugins/geturlnotify-from-npp-destroystream.html
+++ /dev/null
@@ -1,27 +0,0 @@
-<html>
-<script>
-function streamDestroyed()
-{
-    plg.getURL("data:text/html,Stream data");
-}
-
-function runTest() {
-    plg.getURL("/plugins/resources/slow-resource.pl");
-
-    if (window.testRunner) {
-        testRunner.dumpAsText();
-        testRunner.waitUntilDone();
-    }
-
-    var url = 'data:text/html,<scri' + 'pt>if (window.testRunner) testRunner.notifyDone();</scri' + 'pt>';
-    url += '<div>This tests that a plugin that calls NPP_GetURLNotify from its NPP_DestroyStream during teardown '
-    url += 'will not cause a crash.</div><div>SUCCESS! Did not crash!</div>';
-
-    setTimeout(function() { window.location.href = url; }, 100);
-}
-
-</script>
-<body onload="runTest()">
-<embed name="plg" type="application/x-webkit-test-netscape" onstreamdestroy="streamDestroyed()"></embed>
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/plugins/local-geturl-from-remote-expected.txt b/third_party/WebKit/LayoutTests/http/tests/plugins/local-geturl-from-remote-expected.txt
deleted file mode 100644
index 3a3ca13..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/plugins/local-geturl-from-remote-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-CONSOLE ERROR: Not allowed to load local resource: tmp.html
-This tests that a plugin in a remote document can't access local files using NPN_GetURL
-
-FAILURE
diff --git a/third_party/WebKit/LayoutTests/http/tests/plugins/local-geturl-from-remote.html b/third_party/WebKit/LayoutTests/http/tests/plugins/local-geturl-from-remote.html
deleted file mode 100644
index d90c5f9..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/plugins/local-geturl-from-remote.html
+++ /dev/null
@@ -1,36 +0,0 @@
-<html>
-<head>
-<script>
-function notify()
-{
-    if (window.testRunner)
-        testRunner.notifyDone();
-}
-
-function runTest()
-{
-    if (window.testRunner) {
-        testRunner.dumpAsText();
-        testRunner.waitUntilDone();
-    }
-        
-    // No need to let this point to a real file.
-
-    
-    var result = plg.getURL('file:///tmp.html', '_self');
-    if (result == 1)
-        document.getElementById('result').innerHTML = "SUCCESS";
-    else
-        document.getElementById('result').innerHTML = "FAILURE";
-
-    // Round-trip to the plugin once more, so errors can propagate.
-    plg.getURLNotify("resources/load-me-1.txt", null, "notify");
-}
-</script>
-</head>
-<body onload="runTest()">
-<div>This tests that a plugin in a remote document can't access local files using NPN_GetURL</div>
-<embed name="plg" type="application/x-webkit-test-netscape"></embed>
-<div id="result">FAILURE</div>
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/plugins/npapi-response-headers-expected.txt b/third_party/WebKit/LayoutTests/http/tests/plugins/npapi-response-headers-expected.txt
deleted file mode 100644
index 27920cc..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/plugins/npapi-response-headers-expected.txt
+++ /dev/null
@@ -1,16 +0,0 @@
-
-Test for bug 13029: Permit NPAPI plugins to see HTTP response headers.
-
-Expected result below is two HTTP response extracts, one for the initial stream specified in the "src" attribute, the other for an NPN_GetURLNotify request. Each block should contain the URL; the status line, which should say "HTTP 200 OK"; and the MIME-type, which should say "Content-Type: text/plain".
-
-----------
-
-http://[varies, not being tested]/plugins/resources/load-me-1.txt
-HTTP 200 OK
-Content-Type: text/plain
-
-----------
-
-http://[varies, not being tested]/plugins/resources/load-me-2.txt
-HTTP 200 OK
-Content-Type: text/plain
diff --git a/third_party/WebKit/LayoutTests/http/tests/plugins/npapi-response-headers.html b/third_party/WebKit/LayoutTests/http/tests/plugins/npapi-response-headers.html
deleted file mode 100644
index 7eb7460b..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/plugins/npapi-response-headers.html
+++ /dev/null
@@ -1,108 +0,0 @@
-<html>
-<head>
-<script>
-if (window.testRunner) {
-    testRunner.dumpAsText();
-    testRunner.waitUntilDone();
-}
-
-loadedFirstURL = false;
-
-var res1, res2;
-
-function test()
-{
-    try {
-        res1 = document.getElementById("result1");
-        res2 = document.getElementById("result2");
-    } catch (ex) {
-        showErr("Exception: " + ex.description);
-        if (window.testRunner)
-            testRunner.notifyDone();
-    }
-}
-
-function streamLoaded()
-{
-    if (loadedFirstURL)
-        return;
-        
-    loadedFirstURL = true;
-    plg.getURLNotify("/plugins/resources/load-me-2.txt", null, "callback");
-}
-
-function callback(errCode, streamDump)
-{
-    var parse = parseStreamDump(streamDump);
-    if (parse.err)
-        showErr(parse.err);
-    else {
-        res1.innerHTML = newlinesToHTML(parse.res1);
-        res2.innerHTML = newlinesToHTML(parse.res2);
-    }
-
-    if (window.testRunner)
-        testRunner.notifyDone();
-}
-
-// Format passed by plugin: four fields separated by \n\n:
-// First URL; first header block; last URL; last header block.
-function parseStreamDump(streamDump)
-{
-    var rtn = {};
-
-    if (typeof streamDump == "string" || ((typeof streamDump == "object") && (streamDump.constructor == String))) {
-        var parts = streamDump.split("\n\n");
-        if (parts.length >= 4) {
-            rtn.res1 = genericURL(parts[0]) + "\n" + parseHeaders(parts[1]);
-            rtn.res2 = genericURL(parts[2]) + "\n" + parseHeaders(parts[3]);
-        } else
-            rtn.err = "streamDump from plugin does not have expected format";
-    } else
-        rtn.err = "streamDump from plugin is not a string: " + streamDump;
-
-    return rtn;
-}
-
-function showErr(err)
-{
-    res1.innerHTML = "FAILED - " + err;
-    res2.innerHTML = "";
-}
-
-function newlinesToHTML(str)
-{
-    return str.replace(/\n/g, "<br>");
-}
-
-function genericURL(url)
-{
-    return url.replace(/^(http:\/\/)[^\/]+/, "$1[varies, not being tested]");
-}
-
-function parseHeaders(hdrs)
-{
-    var parts = hdrs.split("\n");
-    var rtn = parts[0] + "\n";
-
-    for (var i = 0; i < parts.length; i++)
-        if (parts[i].match(/^Content-Type:/))
-            rtn += parts[i];
-
-    return rtn;
-}
-</script>
-</head>
-<body onload="test()">
-<embed name="plg" type="application/x-webkit-test-netscape" src="/plugins/resources/load-me-1.txt" onstreamload="streamLoaded()"></embed>
-<p>Test for <a href="https://bugs.webkit.org/show_bug.cgi?id=13029">bug 13029<a/>:
-Permit NPAPI plugins to see HTTP response headers.</p>
-<p>Expected result below is two HTTP response extracts, one for the initial stream specified in the "src"
-attribute, the other for an NPN_GetURLNotify request. Each block should contain the URL; the status line,
-which should say "HTTP 200 OK"; and the MIME-type, which should say "Content-Type: text/plain".</p>
-<p>----------</p>
-<p id="result1">Running test, result should appear here in a very short time...</p>
-<p>----------</p>
-<p id="result2">Running test, result should appear here in a very short time...</p>
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/plugins/third-party-cookie-accept-policy-expected.txt b/third_party/WebKit/LayoutTests/http/tests/plugins/third-party-cookie-accept-policy-expected.txt
deleted file mode 100644
index 97b5ec85..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/plugins/third-party-cookie-accept-policy-expected.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-CONSOLE WARNING: Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.
-ALERT: Cookies should be clear, and are: ''
-ALERT: About to set a cookie, but on localhost instead of 127.0.0.1, which is our main document domain - This should fail.
-ALERT: Cookies should still be clear, and are: ''
-This tests that plugins cannot set cookies in violation of the 3rd party cookie policy.
-
diff --git a/third_party/WebKit/LayoutTests/http/tests/plugins/third-party-cookie-accept-policy.html b/third_party/WebKit/LayoutTests/http/tests/plugins/third-party-cookie-accept-policy.html
deleted file mode 100644
index 89c71fb..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/plugins/third-party-cookie-accept-policy.html
+++ /dev/null
@@ -1,18 +0,0 @@
-<html>
-<head>
-<script src="../cookies/resources/resetCookies.js"></script>
-<script>
-resetCookies();
-
-if (window.testRunner) {
-    testRunner.dumpAsText();
-    testRunner.waitUntilDone();
-}
-
-</script>
-<body>
-This tests that plugins cannot set cookies in violation of the 3rd party cookie policy.<br>
-<iframe src="http://localhost:8000/plugins/resources/third-party-cookie-accept-policy-iframe.html"></iframe>
-
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/1.1/report-uri-effective-directive-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/1.1/report-uri-effective-directive-expected.txt
index 54e537e7..69c4de6 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/1.1/report-uri-effective-directive-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/1.1/report-uri-effective-directive-expected.txt
@@ -5,4 +5,4 @@
 HTTP_REFERER: http://127.0.0.1:8000/security/contentSecurityPolicy/1.1/report-uri-effective-directive.html
 REQUEST_METHOD: POST
 === POST DATA ===
-{"csp-report":{"document-uri":"http://127.0.0.1:8000/security/contentSecurityPolicy/1.1/report-uri-effective-directive.html","referrer":"","violated-directive":"default-src 'self'","effective-directive":"script-src","original-policy":"default-src 'self'; report-uri ../resources/save-report.php?test=report-uri-effective-directive.html","blocked-uri":"","status-code":200}}
+{"csp-report":{"document-uri":"http://127.0.0.1:8000/security/contentSecurityPolicy/1.1/report-uri-effective-directive.html","referrer":"","violated-directive":"default-src 'self'","effective-directive":"script-src","original-policy":"default-src 'self'; report-uri ../resources/save-report.php?test=report-uri-effective-directive.html","blocked-uri":"inline","status-code":200}}
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/eval-allowed-in-report-only-mode-and-sends-report-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/eval-allowed-in-report-only-mode-and-sends-report-expected.txt
index 62d866c..7c2dc6e 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/eval-allowed-in-report-only-mode-and-sends-report-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/eval-allowed-in-report-only-mode-and-sends-report-expected.txt
@@ -6,4 +6,4 @@
 HTTP_REFERER: http://127.0.0.1:8000/security/contentSecurityPolicy/eval-allowed-in-report-only-mode-and-sends-report.html
 REQUEST_METHOD: POST
 === POST DATA ===
-{"csp-report":{"document-uri":"http://127.0.0.1:8000/security/contentSecurityPolicy/eval-allowed-in-report-only-mode-and-sends-report.html","referrer":"","violated-directive":"script-src 'self' 'unsafe-inline'","effective-directive":"script-src","original-policy":"script-src 'self' 'unsafe-inline'; report-uri resources/save-report.php?test=eval-allowed-in-report-only-mode-and-sends-report.html","blocked-uri":"","source-file":"http://127.0.0.1:8000/security/contentSecurityPolicy/eval-allowed-in-report-only-mode-and-sends-report.html","line-number":13,"column-number":13,"status-code":200}}
+{"csp-report":{"document-uri":"http://127.0.0.1:8000/security/contentSecurityPolicy/eval-allowed-in-report-only-mode-and-sends-report.html","referrer":"","violated-directive":"script-src 'self' 'unsafe-inline'","effective-directive":"script-src","original-policy":"script-src 'self' 'unsafe-inline'; report-uri resources/save-report.php?test=eval-allowed-in-report-only-mode-and-sends-report.html","blocked-uri":"eval","source-file":"http://127.0.0.1:8000/security/contentSecurityPolicy/eval-allowed-in-report-only-mode-and-sends-report.html","line-number":13,"column-number":13,"status-code":200}}
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/eval-blocked-and-sends-report-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/eval-blocked-and-sends-report-expected.txt
index 9f27ba1..8ecb2be 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/eval-blocked-and-sends-report-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/eval-blocked-and-sends-report-expected.txt
@@ -6,4 +6,4 @@
 HTTP_REFERER: http://127.0.0.1:8000/security/contentSecurityPolicy/eval-blocked-and-sends-report.html
 REQUEST_METHOD: POST
 === POST DATA ===
-{"csp-report":{"document-uri":"http://127.0.0.1:8000/security/contentSecurityPolicy/eval-blocked-and-sends-report.html","referrer":"","violated-directive":"script-src 'self' 'unsafe-inline'","effective-directive":"script-src","original-policy":"script-src 'self' 'unsafe-inline'; report-uri resources/save-report.php?test=eval-blocked-and-sends-report.html","blocked-uri":"","source-file":"http://127.0.0.1:8000/security/contentSecurityPolicy/eval-blocked-and-sends-report.html","line-number":9,"column-number":13,"status-code":200}}
+{"csp-report":{"document-uri":"http://127.0.0.1:8000/security/contentSecurityPolicy/eval-blocked-and-sends-report.html","referrer":"","violated-directive":"script-src 'self' 'unsafe-inline'","effective-directive":"script-src","original-policy":"script-src 'self' 'unsafe-inline'; report-uri resources/save-report.php?test=eval-blocked-and-sends-report.html","blocked-uri":"eval","source-file":"http://127.0.0.1:8000/security/contentSecurityPolicy/eval-blocked-and-sends-report.html","line-number":9,"column-number":13,"status-code":200}}
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/report-and-enforce-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/report-and-enforce-expected.txt
index a1063a7..7af0548 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/report-and-enforce-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/report-and-enforce-expected.txt
@@ -9,4 +9,4 @@
 HTTP_REFERER: http://127.0.0.1:8000/security/contentSecurityPolicy/report-and-enforce.html
 REQUEST_METHOD: POST
 === POST DATA ===
-{"csp-report":{"document-uri":"http://127.0.0.1:8000/security/contentSecurityPolicy/report-and-enforce.html","referrer":"","violated-directive":"script-src 'self'","effective-directive":"script-src","original-policy":"script-src 'self'; report-uri resources/save-report.php?test=report-and-enforce.html","blocked-uri":"","status-code":200}}
+{"csp-report":{"document-uri":"http://127.0.0.1:8000/security/contentSecurityPolicy/report-and-enforce.html","referrer":"","violated-directive":"script-src 'self'","effective-directive":"script-src","original-policy":"script-src 'self'; report-uri resources/save-report.php?test=report-and-enforce.html","blocked-uri":"inline","status-code":200}}
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/report-only-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/report-only-expected.txt
index b27176f..5a3c440f 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/report-only-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/report-only-expected.txt
@@ -7,4 +7,4 @@
 HTTP_REFERER: http://127.0.0.1:8000/security/contentSecurityPolicy/report-only.html
 REQUEST_METHOD: POST
 === POST DATA ===
-{"csp-report":{"document-uri":"http://127.0.0.1:8000/security/contentSecurityPolicy/report-only.html","referrer":"","violated-directive":"script-src 'self'","effective-directive":"script-src","original-policy":"script-src 'self'; report-uri resources/save-report.php?test=report-only.html","blocked-uri":"","status-code":200}}
+{"csp-report":{"document-uri":"http://127.0.0.1:8000/security/contentSecurityPolicy/report-only.html","referrer":"","violated-directive":"script-src 'self'","effective-directive":"script-src","original-policy":"script-src 'self'; report-uri resources/save-report.php?test=report-only.html","blocked-uri":"inline","status-code":200}}
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/report-only-from-header-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/report-only-from-header-expected.txt
index 15bd2fb..22fdca9 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/report-only-from-header-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/report-only-from-header-expected.txt
@@ -6,4 +6,4 @@
 HTTP_REFERER: http://127.0.0.1:8000/security/contentSecurityPolicy/report-only-from-header.php
 REQUEST_METHOD: POST
 === POST DATA ===
-{"csp-report":{"document-uri":"http://127.0.0.1:8000/security/contentSecurityPolicy/report-only-from-header.php","referrer":"","violated-directive":"script-src 'self'","effective-directive":"script-src","original-policy":"script-src 'self'; report-uri resources/save-report.php?test=report-only-from-header.php","blocked-uri":"","status-code":200}}
+{"csp-report":{"document-uri":"http://127.0.0.1:8000/security/contentSecurityPolicy/report-only-from-header.php","referrer":"","violated-directive":"script-src 'self'","effective-directive":"script-src","original-policy":"script-src 'self'; report-uri resources/save-report.php?test=report-only-from-header.php","blocked-uri":"inline","status-code":200}}
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/report-uri-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/report-uri-expected.txt
index b5c28f34..270c7e3 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/report-uri-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/report-uri-expected.txt
@@ -6,4 +6,4 @@
 HTTP_REFERER: http://127.0.0.1:8000/security/contentSecurityPolicy/report-uri.html
 REQUEST_METHOD: POST
 === POST DATA ===
-{"csp-report":{"document-uri":"http://127.0.0.1:8000/security/contentSecurityPolicy/report-uri.html","referrer":"","violated-directive":"script-src 'self'","effective-directive":"script-src","original-policy":"script-src 'self'; report-uri resources/save-report.php?test=report-uri.html","blocked-uri":"","status-code":200}}
+{"csp-report":{"document-uri":"http://127.0.0.1:8000/security/contentSecurityPolicy/report-uri.html","referrer":"","violated-directive":"script-src 'self'","effective-directive":"script-src","original-policy":"script-src 'self'; report-uri resources/save-report.php?test=report-uri.html","blocked-uri":"inline","status-code":200}}
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/report-uri-from-child-frame-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/report-uri-from-child-frame-expected.txt
index 446ae218..d2ff7ba 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/report-uri-from-child-frame-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/report-uri-from-child-frame-expected.txt
@@ -11,4 +11,4 @@
 HTTP_REFERER: http://127.0.0.1:8000/security/contentSecurityPolicy/resources/generate-csp-report.html
 REQUEST_METHOD: POST
 === POST DATA ===
-{"csp-report":{"document-uri":"http://127.0.0.1:8000/security/contentSecurityPolicy/resources/generate-csp-report.html","referrer":"http://127.0.0.1:8000/security/contentSecurityPolicy/report-uri-from-child-frame.html","violated-directive":"script-src 'self'","effective-directive":"script-src","original-policy":"script-src 'self'; report-uri save-report.php?test=generate-csp-report.html","blocked-uri":"","status-code":200}}
+{"csp-report":{"document-uri":"http://127.0.0.1:8000/security/contentSecurityPolicy/resources/generate-csp-report.html","referrer":"http://127.0.0.1:8000/security/contentSecurityPolicy/report-uri-from-child-frame.html","violated-directive":"script-src 'self'","effective-directive":"script-src","original-policy":"script-src 'self'; report-uri save-report.php?test=generate-csp-report.html","blocked-uri":"inline","status-code":200}}
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/report-uri-scheme-relative-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/report-uri-scheme-relative-expected.txt
index 0bcb21e..1f93ac03 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/report-uri-scheme-relative-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/report-uri-scheme-relative-expected.txt
@@ -6,4 +6,4 @@
 HTTP_REFERER: http://127.0.0.1:8000/security/contentSecurityPolicy/report-uri-scheme-relative.html
 REQUEST_METHOD: POST
 === POST DATA ===
-{"csp-report":{"document-uri":"http://127.0.0.1:8000/security/contentSecurityPolicy/report-uri-scheme-relative.html","referrer":"","violated-directive":"script-src 'self'","effective-directive":"script-src","original-policy":"script-src 'self'; report-uri //127.0.0.1:8080/security/contentSecurityPolicy/resources/save-report.php?test=report-uri-scheme-relative.html","blocked-uri":"","status-code":200}}
+{"csp-report":{"document-uri":"http://127.0.0.1:8000/security/contentSecurityPolicy/report-uri-scheme-relative.html","referrer":"","violated-directive":"script-src 'self'","effective-directive":"script-src","original-policy":"script-src 'self'; report-uri //127.0.0.1:8080/security/contentSecurityPolicy/resources/save-report.php?test=report-uri-scheme-relative.html","blocked-uri":"inline","status-code":200}}
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/cross-frame-access-enumeration-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/cross-frame-access-enumeration-expected.txt
index a8e72b0..b0699c32 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/cross-frame-access-enumeration-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/security/cross-frame-access-enumeration-expected.txt
@@ -5,6 +5,6 @@
 PASS: Cross frame access by getting the keys of the window object was denied.
 PASS: Cross frame access by getting the property names of the window object was denied.
 PASS: Cross frame access by enumerating the Location object revealed no properties.
-PASS: Cross frame access by getting the keys of the Location object revealed no keys.
+PASS: Cross frame access by getting the keys of the Location object revealed only whitelisted keys.
 PASS: Cross frame access by getting the property names of the Location object revealed no custom properties.
 
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/cross-frame-access-enumeration.html b/third_party/WebKit/LayoutTests/http/tests/security/cross-frame-access-enumeration.html
index 331798c..b387fdc 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/cross-frame-access-enumeration.html
+++ b/third_party/WebKit/LayoutTests/http/tests/security/cross-frame-access-enumeration.html
@@ -61,16 +61,23 @@
             log("PASS: Cross frame access by enumerating the Location object revealed no properties.");
 
             var b_winLocationKeys = Object.keys(b_win_location);
-            if (b_winLocationKeys.length != 0) {
-                log("FAIL: Cross frame access by getting the keys of the Location object was allowed.");
-                return;
+            var keys_failure = false;
+            for (var i = 0; i < b_winLocationKeys.length; i++) {
+                var k = b_winLocationKeys[i];
+                // See also cross-frame-access-location-get.html for the list of accessible keys.
+                if (k !== "assign" && k !== "replace") {
+                    log("FAIL: Cross frame access by getting the keys of the Location object returned non-whitelisted key: " + k);
+                    keys_failure = true;
+                }
             }
-            log("PASS: Cross frame access by getting the keys of the Location object revealed no keys.");
+            if (!keys_failure) {
+                log("PASS: Cross frame access by getting the keys of the Location object revealed only whitelisted keys.");
+            }
 
             var b_winLocationPropertyNames = Object.getOwnPropertyNames(b_win_location);
             if (b_winLocationPropertyNames.indexOf("customLocationProperty") != -1) {
                 log("FAIL: Cross frame access by getting the property names of the Location object was allowed.");
-                 return;
+                return;
             }
             log("PASS: Cross frame access by getting the property names of the Location object revealed no custom properties.");
         }
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/frameNavigation/resources/frame-with-plugin-to-navigate.html b/third_party/WebKit/LayoutTests/http/tests/security/frameNavigation/resources/frame-with-plugin-to-navigate.html
deleted file mode 100644
index 16120a6..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/security/frameNavigation/resources/frame-with-plugin-to-navigate.html
+++ /dev/null
@@ -1,44 +0,0 @@
-<html>
-<head>
-    <script src="../../resources/cross-frame-access.js"></script>
-    <script>
-        window.onload = function()
-        {
-            document.getElementsByTagName('h4')[0].innerHTML = document.domain;
-            window.addEventListener('message', runTest);
-        }
-
-        runTest = function()
-        {
-            if (!window.testRunner)
-                return;
-
-            plg.getURL("navigation-happened.html", "toNavigate");
-
-            start = new Date();
-            myInterval = setInterval(checkIfDone, 500);
-        }
-
-        checkIfDone = function()
-        {
-            var numOpenWindows = testRunner.windowCount();
-            var now = new Date();
-            if (numOpenWindows == 2) {
-                log("Test PASSED");
-                clearInterval(myInterval);
-                testRunner.notifyDone();            
-            } else if (now - start > 10000) {
-                log('TEST FAILED: Window count ' + numOpenWindows);
-                clearInterval(myInterval);
-                testRunner.notifyDone();
-            }
-        }
-    </script>
-</head>
-<body>
-    <embed name="plg" type="application/x-webkit-test-netscape"></embed>
-    <h3>Frame-with-plugin-to-navigate</h3>
-    <h4>DOMAIN</h4>
-    <pre id='console'></pre>
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/frameNavigation/xss-DENIED-plugin-navigation-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/frameNavigation/xss-DENIED-plugin-navigation-expected.txt
deleted file mode 100644
index caf9d6b..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/security/frameNavigation/xss-DENIED-plugin-navigation-expected.txt
+++ /dev/null
@@ -1,19 +0,0 @@
-CONSOLE ERROR: Unsafe JavaScript attempt to initiate navigation for frame with URL 'http://127.0.0.1:8000/security/resources/cross-frame-iframe.html' from frame with URL 'http://localhost:8000/security/frameNavigation/resources/frame-with-plugin-to-navigate.html'. The frame attempting navigation is neither same-origin with the target, nor is it the target's parent or opener.
-
- 
-
---------
-Frame: '<!--framePath //<!--frame0-->-->'
---------
-
-Frame-with-plugin-to-navigate
-
-localhost
-
-Test PASSED
-
-
---------
-Frame: 'toNavigate'
---------
-Inner iframe.
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/frameNavigation/xss-DENIED-plugin-navigation.html b/third_party/WebKit/LayoutTests/http/tests/security/frameNavigation/xss-DENIED-plugin-navigation.html
deleted file mode 100644
index b53c669..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/security/frameNavigation/xss-DENIED-plugin-navigation.html
+++ /dev/null
@@ -1,23 +0,0 @@
-<html>
-<head>
-    <script src="../resources/cross-frame-access.js"></script>
-    <script>
-        window.onload = function()
-        {
-            if (window.testRunner) {
-                testRunner.dumpAsText();
-                testRunner.dumpChildFramesAsText();
-                testRunner.waitUntilDone();
-                testRunner.setCanOpenWindows();
-                testRunner.setCloseRemainingWindowsWhenComplete(true);
-            }
-            window.frames[0].postMessage('run test', '*');
-        }
-    </script>
-</head>
-<body>
-<pre id='console'></pre>
-<iframe src="http://localhost:8000/security/frameNavigation/resources/frame-with-plugin-to-navigate.html"></iframe>
-<iframe name="toNavigate" src="http://127.0.0.1:8000/security/resources/cross-frame-iframe.html"></iframe>
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/w3c/cross-origin-objects-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/w3c/cross-origin-objects-expected.txt
index 13ec3b87..a4d9bda 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/w3c/cross-origin-objects-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/security/w3c/cross-origin-objects-expected.txt
@@ -8,7 +8,7 @@
 FAIL [[GetOwnProperty]] - Properties on cross-origin objects should be reported |own| Blocked a frame with origin "http://web-platform.test:8000" from accessing a cross-origin frame.
 FAIL [[GetOwnProperty]] - Property descriptors for cross-origin properties should be set up correctly assert_equals: property descriptor for location should be non-enumerable expected false but got true
 PASS [[Delete]] Should throw on cross-origin objects 
-FAIL [[DefineOwnProperty]] Should throw for cross-origin objects assert_throws: Can't define cross-origin value property length function "function () { Object.defineProperty(obj, prop, valueDesc); }" did not throw
+PASS [[DefineOwnProperty]] Should throw for cross-origin objects 
 PASS [[Enumerate]] should return an empty iterator 
 FAIL [[OwnPropertyKeys]] should return all properties from cross-origin objects assert_array_equals: Object.getOwnPropertyNames() gives the right answer for cross-origin Location property 0, expected "href" but got "assign"
 PASS A and B jointly observe the same identity for cross-origin Window and Location 
diff --git a/third_party/WebKit/LayoutTests/http/tests/webfont/css-change-in-swap-period-expected.html b/third_party/WebKit/LayoutTests/http/tests/webfont/css-change-in-swap-period-expected.html
new file mode 100644
index 0000000..4160dc4
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/webfont/css-change-in-swap-period-expected.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<body>
+<style id="target">
+#ref {
+  font-family: Arial;
+  font-size: 50px;
+}
+</style>
+<p>CSS change should not make loading-fallback text blank.</p>
+<div id="ref">abcdefg</div>
+</body>
diff --git a/third_party/WebKit/LayoutTests/http/tests/webfont/css-change-in-swap-period.html b/third_party/WebKit/LayoutTests/http/tests/webfont/css-change-in-swap-period.html
new file mode 100644
index 0000000..ea00bc2
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/webfont/css-change-in-swap-period.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<body>
+<style id="target">
+@font-face {
+  font-family: slow;
+  src: url(slow-ahem-loading.cgi?delay=8000);
+  font-display: fallback;
+}
+.test {
+  font-family: slow, Arial;
+  font-size: 50px;
+}
+</style>
+<p>CSS change should not make loading-fallback text blank.</p>
+<div id="test">abcdefg</div>
+<script>
+
+if (window.testRunner)
+    testRunner.waitUntilDone();
+
+window.onload = function() {
+    document.getElementById('test').classList.add('test');
+    setTimeout(function() {
+        var newStyle = document.createElement('style');
+        newStyle.innerHTML = "@font-face { font-family: dummy; src: local('Courier New'); }";
+        document.body.insertBefore(newStyle, document.getElementById('target'));
+        setTimeout(function() {
+            if (window.testRunner)
+                testRunner.notifyDone();
+        }, 0);
+    }, 500);
+};
+</script>
+</body>
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/FileAPI/url/url_xmlhttprequest-expected.txt b/third_party/WebKit/LayoutTests/imported/web-platform-tests/FileAPI/url/url_xmlhttprequest-expected.txt
index 0e33745a..decd914b 100644
--- a/third_party/WebKit/LayoutTests/imported/web-platform-tests/FileAPI/url/url_xmlhttprequest-expected.txt
+++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/FileAPI/url/url_xmlhttprequest-expected.txt
@@ -1,4 +1,4 @@
 This is a testharness.js-based test.
-FAIL FileAPI Test: Creating Blob URL via XMLHttpRequest assert_true: XMLHttpRequest returns instanceof Blob expected true got false
+FAIL FileAPI Test: Creating Blob URL via XMLHttpRequest Failed to execute 'createObjectURL' on 'URL': No function was found that matched the signature provided.
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/semantics/forms/the-option-element/option-selected-expected.txt b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/semantics/forms/the-option-element/option-selected-expected.txt
deleted file mode 100644
index d49cf74..0000000
--- a/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/semantics/forms/the-option-element/option-selected-expected.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-This is a testharness.js-based test.
-FAIL not dirty assert_equals: expected false but got true
-FAIL dirty, selected assert_equals: expected false but got true
-FAIL dirty, not selected assert_equals: expected false but got true
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/inspector/elements/styles-1/filter-matched-styles-expected.txt b/third_party/WebKit/LayoutTests/inspector/elements/styles-1/filter-matched-styles-expected.txt
index 8f5b3b8..0b01cb2c 100644
--- a/third_party/WebKit/LayoutTests/inspector/elements/styles-1/filter-matched-styles-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/elements/styles-1/filter-matched-styles-expected.txt
@@ -37,6 +37,11 @@
        border-left-color: black
        border-left-style: solid
        border-left-width: 1px
+       border-image-source: initial
+       border-image-slice: initial
+       border-image-width: initial
+       border-image-outset: initial
+       border-image-repeat: initial
    padding:v10px 10px 10px 10px
 F      padding-top: 10px
        padding-right: 10px
diff --git a/third_party/WebKit/LayoutTests/inspector/elements/styles-2/force-pseudo-state-expected.txt b/third_party/WebKit/LayoutTests/inspector/elements/styles-2/force-pseudo-state-expected.txt
index 2eb7706..0721e85 100644
--- a/third_party/WebKit/LayoutTests/inspector/elements/styles-2/force-pseudo-state-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/elements/styles-2/force-pseudo-state-expected.txt
@@ -54,6 +54,11 @@
         border-left-color: green;
         border-left-style: solid;
         border-left-width: 1px;
+        border-image-source: initial;
+        border-image-slice: initial;
+        border-image-width: initial;
+        border-image-outset: initial;
+        border-image-repeat: initial;
 
 [expanded] 
 :focus { (user agent stylesheet)
diff --git a/third_party/WebKit/LayoutTests/inspector/elements/styles-4/styles-properties-overload-expected.txt b/third_party/WebKit/LayoutTests/inspector/elements/styles-4/styles-properties-overload-expected.txt
index c6ba76b..f3e01aa6 100644
--- a/third_party/WebKit/LayoutTests/inspector/elements/styles-4/styles-properties-overload-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/elements/styles-4/styles-properties-overload-expected.txt
@@ -39,6 +39,11 @@
         border-left-color: black;
         border-left-style: solid;
         border-left-width: 1px;
+        border-image-source: initial;
+        border-image-slice: initial;
+        border-image-width: initial;
+        border-image-outset: initial;
+        border-image-repeat: initial;
 
 [expanded] 
 div { (user agent stylesheet)
diff --git a/third_party/WebKit/LayoutTests/inspector/elements/styles-4/styles-update-from-js-expected.txt b/third_party/WebKit/LayoutTests/inspector/elements/styles-4/styles-update-from-js-expected.txt
index 63e9447..9d2d5ca 100644
--- a/third_party/WebKit/LayoutTests/inspector/elements/styles-4/styles-update-from-js-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/elements/styles-4/styles-update-from-js-expected.txt
@@ -21,6 +21,11 @@
         border-left-color: black;
         border-left-style: solid;
         border-left-width: 1px;
+        border-image-source: initial;
+        border-image-slice: initial;
+        border-image-width: initial;
+        border-image-outset: initial;
+        border-image-repeat: initial;
 
 [expanded] 
 div { (user agent stylesheet)
@@ -56,6 +61,11 @@
         border-left-color: green;
         border-left-style: dashed;
         border-left-width: 3px;
+        border-image-source: initial;
+        border-image-slice: initial;
+        border-image-width: initial;
+        border-image-outset: initial;
+        border-image-repeat: initial;
 
 [expanded] 
 div { (user agent stylesheet)
diff --git a/third_party/WebKit/LayoutTests/inspector/file-system-project-expected.txt b/third_party/WebKit/LayoutTests/inspector/file-system-project-expected.txt
index 702987e4..d8664c0 100644
--- a/third_party/WebKit/LayoutTests/inspector/file-system-project-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/file-system-project-expected.txt
@@ -11,19 +11,16 @@
 UISourceCode is content script: false
 Highlighter type: text/javascript
 UISourceCode content: <foo content>
-modificationTime=1000000, size=13
 
 UISourceCode: file:///var/www/bar.js
 UISourceCode is content script: false
 Highlighter type: text/javascript
 UISourceCode content: <bark content>
-modificationTime=1000000, size=14
 
 UISourceCode: file:///foo/bar/baz.js
 UISourceCode is content script: false
 Highlighter type: text/javascript
 UISourceCode content: <bazzz content>
-modificationTime=1000000, size=15
 
 Dumping uiSourceCode location link texts:
  - foo.js:6
@@ -40,11 +37,6 @@
 UISourceCode is content script: false
 Highlighter type: text/javascript
 UISourceCode content: <Modified UISourceCode content>
-New modificationTime=1001000, size=31
-Removing second file system.
-    number of uiSourceCodes in workspace after removing second file system: 1
-Removing first file system.
-    number of uiSourceCodes in workspace after removing first file system: 0
 
 Running: testDefaultExcludes
 
diff --git a/third_party/WebKit/LayoutTests/inspector/file-system-project.html b/third_party/WebKit/LayoutTests/inspector/file-system-project.html
index 6d9f63a3..34d3a73 100644
--- a/third_party/WebKit/LayoutTests/inspector/file-system-project.html
+++ b/third_party/WebKit/LayoutTests/inspector/file-system-project.html
@@ -19,17 +19,7 @@
                 return;
             }
 
-            InspectorTest.dumpUISourceCode(uiSourceCodes[startIndex], dumpCallback.bind(this, uiSourceCodes, startIndex, next));
-            function dumpCallback(uiSourceCodes, startIndex, next)
-            {
-                uiSourceCodes[startIndex].requestMetadata(dumpMetadata.bind(this, uiSourceCodes, startIndex, next));
-            }
-
-            function dumpMetadata(uiSourceCodes, startIndex, next, modificationTime, size)
-            {
-                InspectorTest.addResult("modificationTime=" + modificationTime.getTime() + ", size=" + size);
-                innerDumpUISourceCodes.call(this, uiSourceCodes, startIndex + 1, next);
-            }
+            InspectorTest.dumpUISourceCode(uiSourceCodes[startIndex], innerDumpUISourceCodes.bind(this, uiSourceCodes, startIndex + 1, next));
         }
     }
 
@@ -121,25 +111,14 @@
             function contentCommitted()
             {
                 InspectorTest.addResult("After revision added:");
-                InspectorTest.dumpUISourceCode(uiSourceCodes[0], dumped);
+                InspectorTest.dumpUISourceCode(uiSourceCodes[0], finalize);
+            }
 
-                function dumped()
-                {
-                    uiSourceCodes[0].requestMetadata(dumpModifiedMetadata);
-                }
-
-                function dumpModifiedMetadata(modificationTime, size)
-                {
-                    InspectorTest.addResult("New modificationTime=" + modificationTime.getTime() + ", size=" + size);
-                    var uiSourceCodesCount = InspectorTest.fileSystemUISourceCodes().length;
-                    InspectorTest.addResult("Removing second file system.");
-                    fs1.reportRemoved();
-                    InspectorTest.addResult("    number of uiSourceCodes in workspace after removing second file system: " + InspectorTest.fileSystemUISourceCodes().length);
-                    InspectorTest.addResult("Removing first file system.");
-                    fs2.reportRemoved();
-                    InspectorTest.addResult("    number of uiSourceCodes in workspace after removing first file system: " + InspectorTest.fileSystemUISourceCodes().length);
-                    next();
-                }
+            function finalize()
+            {
+                fs1.reportRemoved();
+                fs2.reportRemoved();
+                next();
             }
         },
 
diff --git a/third_party/WebKit/LayoutTests/inspector/network/network-toggle-type-filter-expected.txt b/third_party/WebKit/LayoutTests/inspector/network/network-toggle-type-filter-expected.txt
index ba17ae9..fb7a4cd 100644
--- a/third_party/WebKit/LayoutTests/inspector/network/network-toggle-type-filter-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/network/network-toggle-type-filter-expected.txt
@@ -2,44 +2,44 @@
 
 
 Clicked 'all' button.
-Filter: xhr: true, fetch: true, eventsource: true, script: true, stylesheet: true, image: true, media: true, font: true, document: true, texttrack: true, websocket: true, other: true
+Filter: xhr: true, fetch: true, eventsource: true, script: true, stylesheet: true, image: true, media: true, font: true, document: true, texttrack: true, websocket: true, other: true, sm-script: true, sm-stylesheet: true
 
 Clicked 'Documents' button.
-Filter: xhr: false, fetch: false, eventsource: false, script: false, stylesheet: false, image: false, media: false, font: false, document: true, texttrack: false, websocket: false, other: false
+Filter: xhr: false, fetch: false, eventsource: false, script: false, stylesheet: false, image: false, media: false, font: false, document: true, texttrack: false, websocket: false, other: false, sm-script: false, sm-stylesheet: false
 
 Clicked 'Documents' button.
-Filter: xhr: false, fetch: false, eventsource: false, script: false, stylesheet: false, image: false, media: false, font: false, document: true, texttrack: false, websocket: false, other: false
+Filter: xhr: false, fetch: false, eventsource: false, script: false, stylesheet: false, image: false, media: false, font: false, document: true, texttrack: false, websocket: false, other: false, sm-script: false, sm-stylesheet: false
 
 Clicked 'Scripts' button.
-Filter: xhr: false, fetch: false, eventsource: false, script: true, stylesheet: false, image: false, media: false, font: false, document: false, texttrack: false, websocket: false, other: false
+Filter: xhr: false, fetch: false, eventsource: false, script: true, stylesheet: false, image: false, media: false, font: false, document: false, texttrack: false, websocket: false, other: false, sm-script: true, sm-stylesheet: false
 
 Toggled 'all' button.
-Filter: xhr: true, fetch: true, eventsource: true, script: true, stylesheet: true, image: true, media: true, font: true, document: true, texttrack: true, websocket: true, other: true
+Filter: xhr: true, fetch: true, eventsource: true, script: true, stylesheet: true, image: true, media: true, font: true, document: true, texttrack: true, websocket: true, other: true, sm-script: true, sm-stylesheet: true
 
 Toggled 'all' button.
-Filter: xhr: true, fetch: true, eventsource: true, script: true, stylesheet: true, image: true, media: true, font: true, document: true, texttrack: true, websocket: true, other: true
+Filter: xhr: true, fetch: true, eventsource: true, script: true, stylesheet: true, image: true, media: true, font: true, document: true, texttrack: true, websocket: true, other: true, sm-script: true, sm-stylesheet: true
 
 Toggled 'Stylesheets' button.
-Filter: xhr: false, fetch: false, eventsource: false, script: false, stylesheet: true, image: false, media: false, font: false, document: false, texttrack: false, websocket: false, other: false
+Filter: xhr: false, fetch: false, eventsource: false, script: false, stylesheet: true, image: false, media: false, font: false, document: false, texttrack: false, websocket: false, other: false, sm-script: false, sm-stylesheet: true
 
 Toggled 'Images' button.
-Filter: xhr: false, fetch: false, eventsource: false, script: false, stylesheet: true, image: true, media: false, font: false, document: false, texttrack: false, websocket: false, other: false
+Filter: xhr: false, fetch: false, eventsource: false, script: false, stylesheet: true, image: true, media: false, font: false, document: false, texttrack: false, websocket: false, other: false, sm-script: false, sm-stylesheet: true
 
 Toggled 'Stylesheets' button.
-Filter: xhr: false, fetch: false, eventsource: false, script: false, stylesheet: false, image: true, media: false, font: false, document: false, texttrack: false, websocket: false, other: false
+Filter: xhr: false, fetch: false, eventsource: false, script: false, stylesheet: false, image: true, media: false, font: false, document: false, texttrack: false, websocket: false, other: false, sm-script: false, sm-stylesheet: false
 
 Clicked 'XHR and Fetch' button.
-Filter: xhr: true, fetch: true, eventsource: true, script: false, stylesheet: false, image: false, media: false, font: false, document: false, texttrack: false, websocket: false, other: false
+Filter: xhr: true, fetch: true, eventsource: true, script: false, stylesheet: false, image: false, media: false, font: false, document: false, texttrack: false, websocket: false, other: false, sm-script: false, sm-stylesheet: false
 
 Toggled 'Fonts' button.
-Filter: xhr: true, fetch: true, eventsource: true, script: false, stylesheet: false, image: false, media: false, font: true, document: false, texttrack: false, websocket: false, other: false
+Filter: xhr: true, fetch: true, eventsource: true, script: false, stylesheet: false, image: false, media: false, font: true, document: false, texttrack: false, websocket: false, other: false, sm-script: false, sm-stylesheet: false
 
 Toggled 'WebSockets' button.
-Filter: xhr: true, fetch: true, eventsource: true, script: false, stylesheet: false, image: false, media: false, font: true, document: false, texttrack: false, websocket: true, other: false
+Filter: xhr: true, fetch: true, eventsource: true, script: false, stylesheet: false, image: false, media: false, font: true, document: false, texttrack: false, websocket: true, other: false, sm-script: false, sm-stylesheet: false
 
 Toggled 'Media' button.
-Filter: xhr: true, fetch: true, eventsource: true, script: false, stylesheet: false, image: false, media: true, font: true, document: false, texttrack: false, websocket: true, other: false
+Filter: xhr: true, fetch: true, eventsource: true, script: false, stylesheet: false, image: false, media: true, font: true, document: false, texttrack: false, websocket: true, other: false, sm-script: false, sm-stylesheet: false
 
 Clicked 'all' button.
-Filter: xhr: true, fetch: true, eventsource: true, script: true, stylesheet: true, image: true, media: true, font: true, document: true, texttrack: true, websocket: true, other: true
+Filter: xhr: true, fetch: true, eventsource: true, script: true, stylesheet: true, image: true, media: true, font: true, document: true, texttrack: true, websocket: true, other: true, sm-script: true, sm-stylesheet: true
 
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/script-snippet-checkContent.html b/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/script-snippet-checkContent.html
index 6c0dee8..ad9b6985 100644
--- a/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/script-snippet-checkContent.html
+++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/script-snippet-checkContent.html
@@ -17,9 +17,9 @@
     window.confirm = confirmOverride;
 
     WebInspector.scriptSnippetModel.project().createFile("", null, "", onCreated.bind(this));
-    function onCreated(path)
+    function onCreated(usc)
     {
-        uiSourceCode = WebInspector.scriptSnippetModel.project().uiSourceCode(path);
+        uiSourceCode = usc;
         uiSourceCode.requestContent(onContentAvailable);
     }
 
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/script-snippet-model.html b/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/script-snippet-model.html
index 59983292..1ead584d 100644
--- a/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/script-snippet-model.html
+++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/script-snippet-model.html
@@ -92,9 +92,9 @@
             
             WebInspector.scriptSnippetModel.project().createFile("", null, "", step2.bind(this));
             
-            function step2(path)
+            function step2(uiSourceCode)
             {
-                uiSourceCode1 = WebInspector.scriptSnippetModel.project().uiSourceCode(path);
+                uiSourceCode1 = uiSourceCode;
                 
                 uiSourceCode1.requestContent(contentCallback);
                 uiSourceCode1.addRevision("<snippet content>");
@@ -107,9 +107,9 @@
                 WebInspector.scriptSnippetModel.project().createFile("", null, "", step3.bind(this));
             }
 
-            function step3(path)
+            function step3(uiSourceCode)
             {
-                var uiSourceCode2 = WebInspector.scriptSnippetModel.project().uiSourceCode(path);
+                var uiSourceCode2 = uiSourceCode;
                 InspectorTest.addResult("Snippet2 created.");
                 renameSnippetAndCheckWorkspace(uiSourceCode1, "foo");
                 renameSnippetAndCheckWorkspace(uiSourceCode1, "   ");
@@ -127,9 +127,9 @@
                 WebInspector.scriptSnippetModel.project().createFile("", null, "", step4.bind(this));
             }
 
-            function step4(path)
+            function step4(uiSourceCode)
             {
-                var uiSourceCode3 = WebInspector.scriptSnippetModel.project().uiSourceCode(path);
+                var uiSourceCode3 = uiSourceCode;
                 InspectorTest.addResult("Snippet3 created.");
                 WebInspector.scriptSnippetModel.project().deleteFile(uiSourceCode3.path());
                 InspectorTest.addResult("Snippet3 deleted.");
@@ -156,9 +156,9 @@
 
             WebInspector.scriptSnippetModel.project().createFile("", null, "", step2.bind(this));
             
-            function step2(path)
+            function step2(uiSourceCode)
             {
-                uiSourceCode1 = WebInspector.scriptSnippetModel.project().uiSourceCode(path);
+                uiSourceCode1 = uiSourceCode;
                 uiSourceCode1.rename("Snippet1", function() { });
                 var content = "";
                 content += "// This snippet does nothing.\n";
@@ -167,9 +167,9 @@
                 WebInspector.scriptSnippetModel.project().createFile("", null, "", step3.bind(this));
             }
             
-            function step3(path)
+            function step3(uiSourceCode)
             {
-                uiSourceCode2 = WebInspector.scriptSnippetModel.project().uiSourceCode(path);
+                uiSourceCode2 = uiSourceCode;
                 uiSourceCode2.rename("Snippet2", function() { });
                 content = "";
                 content += "// This snippet creates a function that does nothing and returns it.\n";
@@ -213,9 +213,9 @@
 
             WebInspector.scriptSnippetModel.project().createFile("", null, "", step3.bind(this));
             
-            function step3(path)
+            function step3(uiSourceCode)
             {
-                var uiSourceCode1 = WebInspector.scriptSnippetModel.project().uiSourceCode(path);
+                var uiSourceCode1 = uiSourceCode;
                 uiSourceCode1.rename("Snippet1", function() { });
                 var content = "";
                 content += "// This snippet does nothing.\n";
@@ -242,9 +242,8 @@
                 WebInspector.scriptSnippetModel.project().createFile("", null, "", step2.bind(this));
             }
 
-            function step2(path)
+            function step2(uiSourceCode)
             {
-                var uiSourceCode = WebInspector.scriptSnippetModel.project().uiSourceCode(path);
                 uiSourceCode.rename("Snippet1", function() { });
                 var content = "2+2;\n";
                 uiSourceCode.setWorkingCopy(content);
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/scripts-panel.html b/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/scripts-panel.html
index 0e495a1..82601fd 100644
--- a/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/scripts-panel.html
+++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/scripts-panel.html
@@ -33,7 +33,7 @@
     function createMockWorkspace()
     {
         InspectorTest.createWorkspaceWithTarget(true);
-        InspectorTest.testDebuggerProjectDelegate = new WebInspector.DebuggerProjectDelegate(InspectorTest.testWorkspace, "debugger:", WebInspector.projectTypes.Debugger);
+        InspectorTest.testDebuggerProject = new WebInspector.ContentProviderBasedProject(InspectorTest.testWorkspace, "", WebInspector.projectTypes.Debugger, "debugger:", "");
         return InspectorTest.testWorkspace;
     }
 
@@ -44,7 +44,7 @@
 
     function addDebuggerFile(workspace, url)
     {
-        var path = InspectorTest.testDebuggerProjectDelegate.addContentProvider("", url, url, createContentProvider(url));
+        var path = InspectorTest.testDebuggerProject.addContentProvider("", url, url, createContentProvider(url));
         return InspectorTest.testWorkspace.uiSourceCode("debugger:", path)
     }
 
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/sources-panel-extension-names-expected.txt b/third_party/WebKit/LayoutTests/inspector/sources/sources-panel-extension-names-expected.txt
index 5175fb1..4a30b4df 100644
--- a/third_party/WebKit/LayoutTests/inspector/sources/sources-panel-extension-names-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/sources/sources-panel-extension-names-expected.txt
@@ -1,12 +1,6 @@
 The test verifies that extension names are resolved properly in navigator view.
 
 
-Running: testAddFileBeforeExecutionContext
-  Dumping ScriptsNavigator contentScripts tab:
-    113581321345589144
-  Dumping ScriptsNavigator contentScripts tab:
-    FibExtension
-
 Running: testAddExecutionContextBeforeFile
   Dumping ScriptsNavigator contentScripts tab:
     FibExtension
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/sources-panel-extension-names.html b/third_party/WebKit/LayoutTests/inspector/sources/sources-panel-extension-names.html
index 3a9f192..c3c9bb2 100644
--- a/third_party/WebKit/LayoutTests/inspector/sources/sources-panel-extension-names.html
+++ b/third_party/WebKit/LayoutTests/inspector/sources/sources-panel-extension-names.html
@@ -19,19 +19,6 @@
     var mockContentScriptURL = mockExecutionContext.origin + "/script.js";
 
     InspectorTest.runTestSuite([
-        function testAddFileBeforeExecutionContext(next)
-        {
-            var contentProvider = new WebInspector.StaticContentProvider(WebInspector.resourceTypes.Script, "");
-            WebInspector.NetworkProject.forTarget(InspectorTest.mainTarget).addFileForURL(mockContentScriptURL, contentProvider, true);
-            InspectorTest.dumpNavigatorView(contentScriptsNavigatorView, "contentScripts", "  ");
-            InspectorTest.runtimeModel._executionContextCreated(mockExecutionContext);
-            InspectorTest.dumpNavigatorView(contentScriptsNavigatorView, "contentScripts", "  ");
-            // cleanup after test
-            WebInspector.NetworkProject.forTarget(InspectorTest.mainTarget)._reset();
-            InspectorTest.runtimeModel._executionContextsCleared();
-            next();
-        },
-
         function testAddExecutionContextBeforeFile(next)
         {
             InspectorTest.runtimeModel._executionContextCreated(mockExecutionContext);
diff --git a/third_party/WebKit/LayoutTests/inspector/uisourcecode-revisions.html b/third_party/WebKit/LayoutTests/inspector/uisourcecode-revisions.html
index 3764549..67414bc 100644
--- a/third_party/WebKit/LayoutTests/inspector/uisourcecode-revisions.html
+++ b/third_party/WebKit/LayoutTests/inspector/uisourcecode-revisions.html
@@ -8,8 +8,8 @@
     function createMockProject()
     {
         var workspace = new WebInspector.Workspace();
-        var projectDelegate = new WebInspector.NetworkProjectDelegate(InspectorTest.mainTarget, workspace, "");
-        var project = workspace.addProject("projectId", projectDelegate);
+        var project = new WebInspector.NetworkProjectDelegate(InspectorTest.mainTarget, workspace, "");
+        workspace.addProject(project);
         project.requestFileContent = function(uri, callback)
         {
             callback("<script content>");
@@ -17,11 +17,6 @@
         project.setFileContent = function(uri, newContent, callback)
         {
         }
-        project.fileMimeType = function(uri)
-        {
-            return "text/javascript";
-        }
-
         return project;
     }
  
diff --git a/third_party/WebKit/LayoutTests/inspector/workspace-mapping-expected.txt b/third_party/WebKit/LayoutTests/inspector/workspace-mapping-expected.txt
index 26ac947..81c41f5b 100644
--- a/third_party/WebKit/LayoutTests/inspector/workspace-mapping-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/workspace-mapping-expected.txt
@@ -5,10 +5,10 @@
     url http://localhost/foo/index.html is mapped.
     url https://localhost/index.html is not mapped.
 
-    url http://www.example.com/index.html is mapped to http://www.example.com/index.html
+    url http://www.example.com/index.html is mapped to null
     url http://localhost/index.html is mapped to filesystem:/var/www/localhost/index.html
     url http://localhost/foo/index.html is mapped to null
-    url https://localhost/index.html is mapped to https://localhost/index.html
+    url https://localhost/index.html is mapped to null
 
     path /home/example.com / foo/index.html is mapped to null
     path /home/example.com / index.html is mapped to null
diff --git a/third_party/WebKit/LayoutTests/inspector/workspace-mapping.html b/third_party/WebKit/LayoutTests/inspector/workspace-mapping.html
index fccbc7a..9c625cb 100644
--- a/third_party/WebKit/LayoutTests/inspector/workspace-mapping.html
+++ b/third_party/WebKit/LayoutTests/inspector/workspace-mapping.html
@@ -6,33 +6,22 @@
 function test()
 {
     var uiSourceCodes = {};
-    var projectDelegates = {};
-    var projectDelegates = {};
+    var projects = {};
+    var workspace = new WebInspector.Workspace();
+
     function createUISourceCode(projectId, path)
     {
-        var projectDelegate = projectDelegates[projectId];
-        if (!projectDelegates[projectId]) {
-            projectDelegate = new MockProjectDelegate(projectId);
-            workspace.addProject(projectId, projectDelegate);
-            projectDelegates[projectId] = projectDelegate;
+        var project = projects[projectId];
+        if (!projects[projectId]) {
+            if (projectId.startsWith("1:"))
+                projectId = projectId.substring(2);
+            project = new WebInspector.ProjectStore(workspace, projectId, WebInspector.projectTypes.Network, projectId, "");
+            workspace.addProject(project);
+            projects[projectId] = project;
         }
-
         var parentPath = path.substring(0, path.lastIndexOf("/"));
         var name = path.substring(path.lastIndexOf("/") + 1);
-        var fileDescriptor = new WebInspector.FileDescriptor(parentPath, name, path, path, WebInspector.resourceTypes.Script);
-        projectDelegate.dispatchEventToListeners(WebInspector.ProjectDelegate.Events.FileAdded, fileDescriptor);
-    }
-
-    function MockProjectDelegate(projectId)
-    {
-        WebInspector.Object.call(this);
-        this._projectId = projectId.startsWith("1:") ? projectId.substring(2) : projectId;
-    }
-    MockProjectDelegate.prototype = {
-        url: function() { return this._projectId; },
-        displayName: function() {},
-        type: function() { return WebInspector.projectTypes.Network; },
-        __proto__: WebInspector.Object.prototype
+        project.addUISourceCode(parentPath, name, path, WebInspector.resourceTypes.Script);
     }
 
     var fileSystemMapping = new WebInspector.FileSystemMapping();
@@ -40,7 +29,6 @@
     var projectId = WebInspector.FileSystemWorkspaceBinding.projectId(fileSystemPath);
     fileSystemMapping.addFileSystem("/var/www");
     fileSystemMapping.addFileMapping("/var/www", "http://localhost/", "/localhost/");
-    var workspace = new WebInspector.Workspace();
     var fileSystemWorkspaceBinding = new WebInspector.FileSystemWorkspaceBinding(WebInspector.isolatedFileSystemManager, workspace);
     var networkMapping = new WebInspector.NetworkMapping(WebInspector.targetManager, workspace, fileSystemWorkspaceBinding, fileSystemMapping);
 
diff --git a/third_party/WebKit/LayoutTests/media/gc-pending-event-inactive-document.html b/third_party/WebKit/LayoutTests/media/gc-pending-event.html
similarity index 67%
rename from third_party/WebKit/LayoutTests/media/gc-pending-event-inactive-document.html
rename to third_party/WebKit/LayoutTests/media/gc-pending-event.html
index 454cee14..6effe6a 100644
--- a/third_party/WebKit/LayoutTests/media/gc-pending-event-inactive-document.html
+++ b/third_party/WebKit/LayoutTests/media/gc-pending-event.html
@@ -1,5 +1,5 @@
 <!DOCTYPE html>
-<title>GC with a pending event in an inactive document</title>
+<title>Verify that a pending event prevents GC</title>
 <script src="../resources/testharness.js"></script>
 <script src="../resources/testharnessreport.js"></script>
 <script src="media-file.js"></script>
@@ -9,11 +9,8 @@
     var a = document.createElement("audio");
     a.volume = 0; // queues a task to fire volumechange
 
-    var doc = document.implementation.createHTMLDocument();
-    doc.body.appendChild(a);
-
     a.onvolumechange = t.step_func_done();
-    a = doc = null;
+    a = null;
     gc();
 });
 </script>
diff --git a/third_party/WebKit/LayoutTests/media/video-move-to-new-document.html b/third_party/WebKit/LayoutTests/media/video-move-to-new-document.html
new file mode 100644
index 0000000..139f701
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/media/video-move-to-new-document.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<title>Verify that moving a video element to a new document, still loads it normally</title>
+<script src="../resources/testharness.js"></script>
+<script src="../resources/testharnessreport.js"></script>
+<script src="media-file.js"></script>
+<video></video>
+<iframe></iframe>
+<script>
+    async_test(function(t) {
+        var video = document.querySelector('video');
+        video.src = findMediaFile("video", "content/test");
+        video.onloadeddata = this.step_func(function() {
+            video.onloadeddata = null;
+            assert_true(video.networkState == video.NETWORK_IDLE || video.networkState == video.NETWORK_LOADING);
+            assert_greater_than(video.readyState, video.HAVE_METADATA);
+            // Move the video element to iframe document from
+            // main document and verify that it loads properly
+            document.querySelector('iframe').contentDocument.body.appendChild(video);
+            assert_equals(video.networkState, video.NETWORK_NO_SOURCE);
+            assert_equals(video.readyState, video.HAVE_NOTHING);
+            var actual_events = [];
+            var expected_events = ['emptied', 'loadstart', 'loadeddata'];
+            expected_events.forEach(function(type) {
+                video.addEventListener(type, t.step_func(function() {
+                    actual_events.push(type);
+                    if (type == 'loadeddata') {
+                        assert_array_equals(actual_events, expected_events);
+                        t.done();
+                    }
+                }));
+            });
+        });
+    });
+</script>
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/repaint/change-text-content-and-background-color-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/fast/repaint/change-text-content-and-background-color-expected.txt
index fd98e29..99e65e6e 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/repaint/change-text-content-and-background-color-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/repaint/change-text-content-and-background-color-expected.txt
@@ -6,14 +6,14 @@
       "contentsOpaque": true,
       "drawsContent": true,
       "repaintRects": [
-        [30, 30, 200, 23],
+        [30, 30, 200, 24],
         [30, 30, 45, 23],
         [30, 30, 41, 23],
         [8, 8, 244, 68]
       ],
       "paintInvalidationClients": [
-        "InlineTextBox ''",
         "RootInlineBox",
+        "InlineTextBox ''",
         "LayoutTextControl (positioned) INPUT id='input'",
         "LayoutBlockFlow DIV id='inner-editor'",
         "LayoutText #text",
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/repaint/multi-layout-one-frame-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/fast/repaint/multi-layout-one-frame-expected.txt
index 346aab1..53a8e030 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/repaint/multi-layout-one-frame-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/repaint/multi-layout-one-frame-expected.txt
@@ -14,10 +14,10 @@
         [10, 11, 45, 16]
       ],
       "paintInvalidationClients": [
-        "InlineTextBox ''",
         "RootInlineBox",
         "InlineTextBox ''",
         "RootInlineBox",
+        "InlineTextBox ''",
         "LayoutBlockFlow DIV id='inner-editor'",
         "LayoutText #text",
         "InlineTextBox 'PASSED'",
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/repaint/subtree-root-skipped-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/fast/repaint/subtree-root-skipped-expected.txt
index d3ffcb7..cf76b15 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/repaint/subtree-root-skipped-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/repaint/subtree-root-skipped-expected.txt
@@ -13,8 +13,8 @@
         [8, 288, 10, 20]
       ],
       "paintInvalidationClients": [
-        "InlineTextBox ''",
         "RootInlineBox",
+        "InlineTextBox ''",
         "LayoutBlockFlow DIV id='inner-editor'",
         "LayoutText #text",
         "InlineTextBox 'PASS'",
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/syncpaint/fast/repaint/change-text-content-and-background-color-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/syncpaint/fast/repaint/change-text-content-and-background-color-expected.txt
new file mode 100644
index 0000000..99e65e6e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/syncpaint/fast/repaint/change-text-content-and-background-color-expected.txt
@@ -0,0 +1,25 @@
+{
+  "bounds": [800, 600],
+  "children": [
+    {
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "drawsContent": true,
+      "repaintRects": [
+        [30, 30, 200, 24],
+        [30, 30, 45, 23],
+        [30, 30, 41, 23],
+        [8, 8, 244, 68]
+      ],
+      "paintInvalidationClients": [
+        "RootInlineBox",
+        "InlineTextBox ''",
+        "LayoutTextControl (positioned) INPUT id='input'",
+        "LayoutBlockFlow DIV id='inner-editor'",
+        "LayoutText #text",
+        "InlineTextBox 'NEW'"
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/syncpaint/fast/repaint/multi-layout-one-frame-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/syncpaint/fast/repaint/multi-layout-one-frame-expected.txt
new file mode 100644
index 0000000..53a8e030
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/syncpaint/fast/repaint/multi-layout-one-frame-expected.txt
@@ -0,0 +1,31 @@
+{
+  "bounds": [800, 600],
+  "children": [
+    {
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "drawsContent": true,
+      "repaintRects": [
+        [168, 11, 150, 16],
+        [168, 11, 53, 16],
+        [168, 11, 45, 16],
+        [10, 11, 150, 16],
+        [10, 11, 53, 16],
+        [10, 11, 45, 16]
+      ],
+      "paintInvalidationClients": [
+        "RootInlineBox",
+        "InlineTextBox ''",
+        "RootInlineBox",
+        "InlineTextBox ''",
+        "LayoutBlockFlow DIV id='inner-editor'",
+        "LayoutText #text",
+        "InlineTextBox 'PASSED'",
+        "LayoutBlockFlow DIV id='inner-editor'",
+        "LayoutText #text",
+        "InlineTextBox 'PASSED'"
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/syncpaint/fast/repaint/subtree-root-skipped-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/syncpaint/fast/repaint/subtree-root-skipped-expected.txt
new file mode 100644
index 0000000..cf76b15
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/syncpaint/fast/repaint/subtree-root-skipped-expected.txt
@@ -0,0 +1,26 @@
+{
+  "bounds": [800, 600],
+  "children": [
+    {
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "drawsContent": true,
+      "repaintRects": [
+        [10, 11, 150, 16],
+        [10, 11, 35, 16],
+        [10, 11, 27, 16],
+        [8, 298, 10, 10],
+        [8, 288, 10, 20]
+      ],
+      "paintInvalidationClients": [
+        "RootInlineBox",
+        "InlineTextBox ''",
+        "LayoutBlockFlow DIV id='inner-editor'",
+        "LayoutText #text",
+        "InlineTextBox 'PASS'",
+        "LayoutBlockFlow (positioned) DIV id='div'"
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/repaint/change-text-content-and-background-color-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/repaint/change-text-content-and-background-color-expected.txt
index d4c3d7c..fd1212d 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/repaint/change-text-content-and-background-color-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/repaint/change-text-content-and-background-color-expected.txt
@@ -12,8 +12,8 @@
         [8, 8, 244, 67]
       ],
       "paintInvalidationClients": [
-        "InlineTextBox ''",
         "RootInlineBox",
+        "InlineTextBox ''",
         "LayoutTextControl (positioned) INPUT id='input'",
         "LayoutBlockFlow DIV id='inner-editor'",
         "LayoutText #text",
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/repaint/multi-layout-one-frame-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/repaint/multi-layout-one-frame-expected.txt
index 430fc53..a44c99a2 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/repaint/multi-layout-one-frame-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/repaint/multi-layout-one-frame-expected.txt
@@ -14,10 +14,10 @@
         [11, 11, 37, 13]
       ],
       "paintInvalidationClients": [
-        "InlineTextBox ''",
         "RootInlineBox",
         "InlineTextBox ''",
         "RootInlineBox",
+        "InlineTextBox ''",
         "LayoutBlockFlow DIV id='inner-editor'",
         "LayoutText #text",
         "InlineTextBox 'PASSED'",
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/repaint/subtree-root-skipped-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/repaint/subtree-root-skipped-expected.txt
index 247f8f7..a357e7f 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/repaint/subtree-root-skipped-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/repaint/subtree-root-skipped-expected.txt
@@ -13,8 +13,8 @@
         [8, 288, 10, 20]
       ],
       "paintInvalidationClients": [
-        "InlineTextBox ''",
         "RootInlineBox",
+        "InlineTextBox ''",
         "LayoutBlockFlow DIV id='inner-editor'",
         "LayoutText #text",
         "InlineTextBox 'PASS'",
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mavericks/virtual/syncpaint/fast/repaint/change-text-content-and-background-color-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mavericks/virtual/syncpaint/fast/repaint/change-text-content-and-background-color-expected.txt
new file mode 100644
index 0000000..fd1212d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac-mavericks/virtual/syncpaint/fast/repaint/change-text-content-and-background-color-expected.txt
@@ -0,0 +1,25 @@
+{
+  "bounds": [800, 600],
+  "children": [
+    {
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "drawsContent": true,
+      "repaintRects": [
+        [30, 30, 200, 23],
+        [30, 30, 43, 23],
+        [30, 30, 42, 23],
+        [8, 8, 244, 67]
+      ],
+      "paintInvalidationClients": [
+        "RootInlineBox",
+        "InlineTextBox ''",
+        "LayoutTextControl (positioned) INPUT id='input'",
+        "LayoutBlockFlow DIV id='inner-editor'",
+        "LayoutText #text",
+        "InlineTextBox 'NEW'"
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mavericks/virtual/syncpaint/fast/repaint/multi-layout-one-frame-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mavericks/virtual/syncpaint/fast/repaint/multi-layout-one-frame-expected.txt
new file mode 100644
index 0000000..a44c99a2
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac-mavericks/virtual/syncpaint/fast/repaint/multi-layout-one-frame-expected.txt
@@ -0,0 +1,31 @@
+{
+  "bounds": [800, 600],
+  "children": [
+    {
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "drawsContent": true,
+      "repaintRects": [
+        [138, 11, 117, 13],
+        [138, 11, 40, 13],
+        [138, 11, 37, 13],
+        [11, 11, 117, 13],
+        [11, 11, 40, 13],
+        [11, 11, 37, 13]
+      ],
+      "paintInvalidationClients": [
+        "RootInlineBox",
+        "InlineTextBox ''",
+        "RootInlineBox",
+        "InlineTextBox ''",
+        "LayoutBlockFlow DIV id='inner-editor'",
+        "LayoutText #text",
+        "InlineTextBox 'PASSED'",
+        "LayoutBlockFlow DIV id='inner-editor'",
+        "LayoutText #text",
+        "InlineTextBox 'PASSED'"
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mavericks/virtual/syncpaint/fast/repaint/subtree-root-skipped-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mavericks/virtual/syncpaint/fast/repaint/subtree-root-skipped-expected.txt
new file mode 100644
index 0000000..a357e7f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac-mavericks/virtual/syncpaint/fast/repaint/subtree-root-skipped-expected.txt
@@ -0,0 +1,26 @@
+{
+  "bounds": [800, 600],
+  "children": [
+    {
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "drawsContent": true,
+      "repaintRects": [
+        [11, 11, 117, 13],
+        [11, 11, 26, 13],
+        [11, 11, 23, 13],
+        [8, 298, 10, 10],
+        [8, 288, 10, 20]
+      ],
+      "paintInvalidationClients": [
+        "RootInlineBox",
+        "InlineTextBox ''",
+        "LayoutBlockFlow DIV id='inner-editor'",
+        "LayoutText #text",
+        "InlineTextBox 'PASS'",
+        "LayoutBlockFlow (positioned) DIV id='div'"
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/change-text-content-and-background-color-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/change-text-content-and-background-color-expected.txt
index bb90eaaf1..172b7d20 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/change-text-content-and-background-color-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/change-text-content-and-background-color-expected.txt
@@ -12,8 +12,8 @@
         [8, 8, 244, 67]
       ],
       "paintInvalidationClients": [
-        "InlineTextBox ''",
         "RootInlineBox",
+        "InlineTextBox ''",
         "LayoutTextControl (positioned) INPUT id='input'",
         "LayoutBlockFlow DIV id='inner-editor'",
         "LayoutText #text",
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/multi-layout-one-frame-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/multi-layout-one-frame-expected.txt
index 604b122..5d90b9ad 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/multi-layout-one-frame-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/multi-layout-one-frame-expected.txt
@@ -14,10 +14,10 @@
         [11, 11, 37, 13]
       ],
       "paintInvalidationClients": [
-        "InlineTextBox ''",
         "RootInlineBox",
         "InlineTextBox ''",
         "RootInlineBox",
+        "InlineTextBox ''",
         "LayoutBlockFlow DIV id='inner-editor'",
         "LayoutText #text",
         "InlineTextBox 'PASSED'",
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/subtree-root-skipped-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/subtree-root-skipped-expected.txt
index 3f32cc3..5f8471b 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/subtree-root-skipped-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/subtree-root-skipped-expected.txt
@@ -13,8 +13,8 @@
         [8, 288, 10, 20]
       ],
       "paintInvalidationClients": [
-        "InlineTextBox ''",
         "RootInlineBox",
+        "InlineTextBox ''",
         "LayoutBlockFlow DIV id='inner-editor'",
         "LayoutText #text",
         "InlineTextBox 'PASS'",
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/syncpaint/fast/repaint/change-text-content-and-background-color-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/syncpaint/fast/repaint/change-text-content-and-background-color-expected.txt
new file mode 100644
index 0000000..172b7d20
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/syncpaint/fast/repaint/change-text-content-and-background-color-expected.txt
@@ -0,0 +1,25 @@
+{
+  "bounds": [800, 600],
+  "children": [
+    {
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "drawsContent": true,
+      "repaintRects": [
+        [30, 30, 200, 23],
+        [30, 30, 46, 23],
+        [30, 30, 42, 23],
+        [8, 8, 244, 67]
+      ],
+      "paintInvalidationClients": [
+        "RootInlineBox",
+        "InlineTextBox ''",
+        "LayoutTextControl (positioned) INPUT id='input'",
+        "LayoutBlockFlow DIV id='inner-editor'",
+        "LayoutText #text",
+        "InlineTextBox 'NEW'"
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/syncpaint/fast/repaint/multi-layout-one-frame-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/syncpaint/fast/repaint/multi-layout-one-frame-expected.txt
new file mode 100644
index 0000000..5d90b9ad
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/syncpaint/fast/repaint/multi-layout-one-frame-expected.txt
@@ -0,0 +1,31 @@
+{
+  "bounds": [800, 600],
+  "children": [
+    {
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "drawsContent": true,
+      "repaintRects": [
+        [146, 11, 125, 13],
+        [146, 11, 43, 13],
+        [146, 11, 37, 13],
+        [11, 11, 125, 13],
+        [11, 11, 43, 13],
+        [11, 11, 37, 13]
+      ],
+      "paintInvalidationClients": [
+        "RootInlineBox",
+        "InlineTextBox ''",
+        "RootInlineBox",
+        "InlineTextBox ''",
+        "LayoutBlockFlow DIV id='inner-editor'",
+        "LayoutText #text",
+        "InlineTextBox 'PASSED'",
+        "LayoutBlockFlow DIV id='inner-editor'",
+        "LayoutText #text",
+        "InlineTextBox 'PASSED'"
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/syncpaint/fast/repaint/subtree-root-skipped-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/syncpaint/fast/repaint/subtree-root-skipped-expected.txt
new file mode 100644
index 0000000..5f8471b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/syncpaint/fast/repaint/subtree-root-skipped-expected.txt
@@ -0,0 +1,26 @@
+{
+  "bounds": [800, 600],
+  "children": [
+    {
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "drawsContent": true,
+      "repaintRects": [
+        [11, 11, 125, 13],
+        [11, 11, 29, 13],
+        [11, 11, 23, 13],
+        [8, 298, 10, 10],
+        [8, 288, 10, 20]
+      ],
+      "paintInvalidationClients": [
+        "RootInlineBox",
+        "InlineTextBox ''",
+        "LayoutBlockFlow DIV id='inner-editor'",
+        "LayoutText #text",
+        "InlineTextBox 'PASS'",
+        "LayoutBlockFlow (positioned) DIV id='div'"
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/fast/repaint/change-text-content-and-background-color-expected.txt b/third_party/WebKit/LayoutTests/platform/win-xp/fast/repaint/change-text-content-and-background-color-expected.txt
index fd98e29..99e65e6e 100644
--- a/third_party/WebKit/LayoutTests/platform/win-xp/fast/repaint/change-text-content-and-background-color-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/fast/repaint/change-text-content-and-background-color-expected.txt
@@ -6,14 +6,14 @@
       "contentsOpaque": true,
       "drawsContent": true,
       "repaintRects": [
-        [30, 30, 200, 23],
+        [30, 30, 200, 24],
         [30, 30, 45, 23],
         [30, 30, 41, 23],
         [8, 8, 244, 68]
       ],
       "paintInvalidationClients": [
-        "InlineTextBox ''",
         "RootInlineBox",
+        "InlineTextBox ''",
         "LayoutTextControl (positioned) INPUT id='input'",
         "LayoutBlockFlow DIV id='inner-editor'",
         "LayoutText #text",
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/fast/repaint/multi-layout-one-frame-expected.txt b/third_party/WebKit/LayoutTests/platform/win-xp/fast/repaint/multi-layout-one-frame-expected.txt
index f581c766..ddd172ef 100644
--- a/third_party/WebKit/LayoutTests/platform/win-xp/fast/repaint/multi-layout-one-frame-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/fast/repaint/multi-layout-one-frame-expected.txt
@@ -14,10 +14,10 @@
         [10, 11, 45, 16]
       ],
       "paintInvalidationClients": [
-        "InlineTextBox ''",
         "RootInlineBox",
         "InlineTextBox ''",
         "RootInlineBox",
+        "InlineTextBox ''",
         "LayoutBlockFlow DIV id='inner-editor'",
         "LayoutText #text",
         "InlineTextBox 'PASSED'",
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/fast/repaint/subtree-root-skipped-expected.txt b/third_party/WebKit/LayoutTests/platform/win-xp/fast/repaint/subtree-root-skipped-expected.txt
index 98ab6082..cae1954 100644
--- a/third_party/WebKit/LayoutTests/platform/win-xp/fast/repaint/subtree-root-skipped-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/fast/repaint/subtree-root-skipped-expected.txt
@@ -13,8 +13,8 @@
         [8, 288, 10, 20]
       ],
       "paintInvalidationClients": [
-        "InlineTextBox ''",
         "RootInlineBox",
+        "InlineTextBox ''",
         "LayoutBlockFlow DIV id='inner-editor'",
         "LayoutText #text",
         "InlineTextBox 'PASS'",
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/virtual/syncpaint/fast/repaint/change-text-content-and-background-color-expected.txt b/third_party/WebKit/LayoutTests/platform/win-xp/virtual/syncpaint/fast/repaint/change-text-content-and-background-color-expected.txt
new file mode 100644
index 0000000..99e65e6e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/virtual/syncpaint/fast/repaint/change-text-content-and-background-color-expected.txt
@@ -0,0 +1,25 @@
+{
+  "bounds": [800, 600],
+  "children": [
+    {
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "drawsContent": true,
+      "repaintRects": [
+        [30, 30, 200, 24],
+        [30, 30, 45, 23],
+        [30, 30, 41, 23],
+        [8, 8, 244, 68]
+      ],
+      "paintInvalidationClients": [
+        "RootInlineBox",
+        "InlineTextBox ''",
+        "LayoutTextControl (positioned) INPUT id='input'",
+        "LayoutBlockFlow DIV id='inner-editor'",
+        "LayoutText #text",
+        "InlineTextBox 'NEW'"
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/virtual/syncpaint/fast/repaint/multi-layout-one-frame-expected.txt b/third_party/WebKit/LayoutTests/platform/win-xp/virtual/syncpaint/fast/repaint/multi-layout-one-frame-expected.txt
new file mode 100644
index 0000000..ddd172ef
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/virtual/syncpaint/fast/repaint/multi-layout-one-frame-expected.txt
@@ -0,0 +1,31 @@
+{
+  "bounds": [800, 600],
+  "children": [
+    {
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "drawsContent": true,
+      "repaintRects": [
+        [167, 11, 149, 16],
+        [167, 11, 54, 16],
+        [167, 11, 45, 16],
+        [10, 11, 149, 16],
+        [10, 11, 54, 16],
+        [10, 11, 45, 16]
+      ],
+      "paintInvalidationClients": [
+        "RootInlineBox",
+        "InlineTextBox ''",
+        "RootInlineBox",
+        "InlineTextBox ''",
+        "LayoutBlockFlow DIV id='inner-editor'",
+        "LayoutText #text",
+        "InlineTextBox 'PASSED'",
+        "LayoutBlockFlow DIV id='inner-editor'",
+        "LayoutText #text",
+        "InlineTextBox 'PASSED'"
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/virtual/syncpaint/fast/repaint/subtree-root-skipped-expected.txt b/third_party/WebKit/LayoutTests/platform/win-xp/virtual/syncpaint/fast/repaint/subtree-root-skipped-expected.txt
new file mode 100644
index 0000000..cae1954
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/win-xp/virtual/syncpaint/fast/repaint/subtree-root-skipped-expected.txt
@@ -0,0 +1,26 @@
+{
+  "bounds": [800, 600],
+  "children": [
+    {
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "drawsContent": true,
+      "repaintRects": [
+        [10, 11, 149, 16],
+        [10, 11, 36, 16],
+        [10, 11, 27, 16],
+        [8, 298, 10, 10],
+        [8, 288, 10, 20]
+      ],
+      "paintInvalidationClients": [
+        "RootInlineBox",
+        "InlineTextBox ''",
+        "LayoutBlockFlow DIV id='inner-editor'",
+        "LayoutText #text",
+        "InlineTextBox 'PASS'",
+        "LayoutBlockFlow (positioned) DIV id='div'"
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/repaint/change-text-content-and-background-color-expected.txt b/third_party/WebKit/LayoutTests/platform/win/fast/repaint/change-text-content-and-background-color-expected.txt
index d1c5dea..3f07ce1 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/repaint/change-text-content-and-background-color-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/repaint/change-text-content-and-background-color-expected.txt
@@ -6,14 +6,14 @@
       "contentsOpaque": true,
       "drawsContent": true,
       "repaintRects": [
-        [30, 30, 200, 22],
+        [30, 30, 200, 23],
         [30, 30, 47, 22],
         [30, 30, 42, 22],
         [8, 8, 244, 67]
       ],
       "paintInvalidationClients": [
-        "InlineTextBox ''",
         "RootInlineBox",
+        "InlineTextBox ''",
         "LayoutTextControl (positioned) INPUT id='input'",
         "LayoutBlockFlow DIV id='inner-editor'",
         "LayoutText #text",
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/repaint/multi-layout-one-frame-expected.txt b/third_party/WebKit/LayoutTests/platform/win/fast/repaint/multi-layout-one-frame-expected.txt
index e11c0b7..50cd6d2c 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/repaint/multi-layout-one-frame-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/repaint/multi-layout-one-frame-expected.txt
@@ -14,10 +14,10 @@
         [10, 11, 45, 16]
       ],
       "paintInvalidationClients": [
-        "InlineTextBox ''",
         "RootInlineBox",
         "InlineTextBox ''",
         "RootInlineBox",
+        "InlineTextBox ''",
         "LayoutBlockFlow DIV id='inner-editor'",
         "LayoutText #text",
         "InlineTextBox 'PASSED'",
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/repaint/subtree-root-skipped-expected.txt b/third_party/WebKit/LayoutTests/platform/win/fast/repaint/subtree-root-skipped-expected.txt
index 88c9f63..73eee651 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/repaint/subtree-root-skipped-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/repaint/subtree-root-skipped-expected.txt
@@ -13,8 +13,8 @@
         [8, 288, 10, 20]
       ],
       "paintInvalidationClients": [
-        "InlineTextBox ''",
         "RootInlineBox",
+        "InlineTextBox ''",
         "LayoutBlockFlow DIV id='inner-editor'",
         "LayoutText #text",
         "InlineTextBox 'PASS'",
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/syncpaint/fast/repaint/change-text-content-and-background-color-expected.txt b/third_party/WebKit/LayoutTests/platform/win/virtual/syncpaint/fast/repaint/change-text-content-and-background-color-expected.txt
new file mode 100644
index 0000000..3f07ce1
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/syncpaint/fast/repaint/change-text-content-and-background-color-expected.txt
@@ -0,0 +1,25 @@
+{
+  "bounds": [800, 600],
+  "children": [
+    {
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "drawsContent": true,
+      "repaintRects": [
+        [30, 30, 200, 23],
+        [30, 30, 47, 22],
+        [30, 30, 42, 22],
+        [8, 8, 244, 67]
+      ],
+      "paintInvalidationClients": [
+        "RootInlineBox",
+        "InlineTextBox ''",
+        "LayoutTextControl (positioned) INPUT id='input'",
+        "LayoutBlockFlow DIV id='inner-editor'",
+        "LayoutText #text",
+        "InlineTextBox 'NEW'"
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/syncpaint/fast/repaint/multi-layout-one-frame-expected.txt b/third_party/WebKit/LayoutTests/platform/win/virtual/syncpaint/fast/repaint/multi-layout-one-frame-expected.txt
new file mode 100644
index 0000000..50cd6d2c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/syncpaint/fast/repaint/multi-layout-one-frame-expected.txt
@@ -0,0 +1,31 @@
+{
+  "bounds": [800, 600],
+  "children": [
+    {
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "drawsContent": true,
+      "repaintRects": [
+        [187, 11, 169, 16],
+        [187, 11, 53, 16],
+        [187, 11, 45, 16],
+        [10, 11, 169, 16],
+        [10, 11, 53, 16],
+        [10, 11, 45, 16]
+      ],
+      "paintInvalidationClients": [
+        "RootInlineBox",
+        "InlineTextBox ''",
+        "RootInlineBox",
+        "InlineTextBox ''",
+        "LayoutBlockFlow DIV id='inner-editor'",
+        "LayoutText #text",
+        "InlineTextBox 'PASSED'",
+        "LayoutBlockFlow DIV id='inner-editor'",
+        "LayoutText #text",
+        "InlineTextBox 'PASSED'"
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/syncpaint/fast/repaint/subtree-root-skipped-expected.txt b/third_party/WebKit/LayoutTests/platform/win/virtual/syncpaint/fast/repaint/subtree-root-skipped-expected.txt
new file mode 100644
index 0000000..73eee651
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/syncpaint/fast/repaint/subtree-root-skipped-expected.txt
@@ -0,0 +1,26 @@
+{
+  "bounds": [800, 600],
+  "children": [
+    {
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "drawsContent": true,
+      "repaintRects": [
+        [10, 11, 169, 16],
+        [10, 11, 35, 16],
+        [10, 11, 27, 16],
+        [8, 298, 10, 10],
+        [8, 288, 10, 20]
+      ],
+      "paintInvalidationClients": [
+        "RootInlineBox",
+        "InlineTextBox ''",
+        "LayoutBlockFlow DIV id='inner-editor'",
+        "LayoutText #text",
+        "InlineTextBox 'PASS'",
+        "LayoutBlockFlow (positioned) DIV id='div'"
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/WebKit/LayoutTests/plugins/document-open-expected.txt b/third_party/WebKit/LayoutTests/plugins/document-open-expected.txt
deleted file mode 100644
index 8b13789..0000000
--- a/third_party/WebKit/LayoutTests/plugins/document-open-expected.txt
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/third_party/WebKit/LayoutTests/plugins/document-open.html b/third_party/WebKit/LayoutTests/plugins/document-open.html
deleted file mode 100644
index 1d0d39d..0000000
--- a/third_party/WebKit/LayoutTests/plugins/document-open.html
+++ /dev/null
@@ -1,20 +0,0 @@
-<html>
-<head>
-<body>
-<embed id="testPlugin" 
-       type="application/x-webkit-test-netscape"
-       src="data:text/plain,"
-       test="document-open-in-destroy-stream">
-</embed>
-
-<div>
-    This tests that document.open invoked by a plugin via NPN_Invoke without a javascript context succeeds.
-</div>
-<script>
-  if (window.testRunner) {
-      testRunner.dumpAsText();
-      testRunner.waitUntilDone();
-  }
-</script>
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/plugins/embed-inside-object-expected.txt b/third_party/WebKit/LayoutTests/plugins/embed-inside-object-expected.txt
deleted file mode 100644
index 93e31b3f..0000000
--- a/third_party/WebKit/LayoutTests/plugins/embed-inside-object-expected.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-
-This tests that it's possible to control an embed that is nested inside an object with a span tag in between.
-plugin object is: [object HTMLEmbedElement]
-SUCCESS
-
diff --git a/third_party/WebKit/LayoutTests/plugins/embed-inside-object.html b/third_party/WebKit/LayoutTests/plugins/embed-inside-object.html
deleted file mode 100644
index dfc0da3d..0000000
--- a/third_party/WebKit/LayoutTests/plugins/embed-inside-object.html
+++ /dev/null
@@ -1,37 +0,0 @@
-<html>
-<script>
-    function debug(str) {
-        document.getElementById('console').innerHTML += str + "<br>";
-    }
-    
-    function pluginCallback() {
-        debug('SUCCESS');
-        if (window.testRunner)
-            testRunner.notifyDone();
-    }
-    
-    function runTest() {
-        if (window.testRunner) {
-            testRunner.dumpAsText();
-            testRunner.waitUntilDone();
-        }
-        
-        var plugin = document.plugin;
-    
-        debug('plugin object is: ' + plugin);
-        plugin.getURL('javascript:pluginCallback()', '_self')
-    }
-</script>
-<body onload="runTest()">
-<object name="plugin" type="application/x-webkit-test-netscape">
-    <span>
-        <embed name="plugin" type="application/x-webkit-test-netscape"></embed>
-    </span>
-</object>
-<div>
-    This tests that it's possible to control an embed that is nested inside an object with a span tag in between.
-</div>
-<div id="console">
-</div>
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/transforms/perspective-origin-parsing.html b/third_party/WebKit/LayoutTests/transforms/perspective-origin-parsing.html
index 8eb82d1..5eb8c2e 100644
--- a/third_party/WebKit/LayoutTests/transforms/perspective-origin-parsing.html
+++ b/third_party/WebKit/LayoutTests/transforms/perspective-origin-parsing.html
@@ -9,14 +9,14 @@
 expect('initial').parsesAs('initial').isComputedTo('100px 50px');
 expect('inherit').parsesAs('inherit');
 
-expect('left').parsesAs('left 50%').isComputedTo('0px 50px');
-expect('center').parsesAs('center 50%').isComputedTo('100px 50px');
-expect('right').parsesAs('right 50%').isComputedTo('200px 50px');
-expect('top').parsesAs('50% top');
-expect('bottom').parsesAs('50% bottom');
-expect('0').parsesAs('0px 50%');
-expect('10%').parsesAs('10% 50%').isComputedTo('20px 50px');
-expect('10px').parsesAs('10px 50%').isComputedTo('10px 50px');
+expect('left').parsesAs('left center').isComputedTo('0px 50px');
+expect('center').parsesAs('center center').isComputedTo('100px 50px');
+expect('right').parsesAs('right center').isComputedTo('200px 50px');
+expect('top').parsesAs('center top');
+expect('bottom').parsesAs('center bottom');
+expect('0').parsesAs('0px center');
+expect('10%').parsesAs('10% center').isComputedTo('20px 50px');
+expect('10px').parsesAs('10px center').isComputedTo('10px 50px');
 
 expect('left top').parsesAs('left top');
 expect('right bottom').parsesAs('right bottom');
@@ -36,6 +36,14 @@
 expect('0px bottom').parsesAs('0px bottom').isComputedTo('0px 100px');
 expect('0px center').parsesAs('0px center').isComputedTo('0px 50px');
 
+expect('center right 20%').parsesAs('right 20% center');
+expect('left bottom 30px').parsesAs('left bottom 30px');
+expect('top right 30px').parsesAs('right 30px top');
+
+expect('left 30px bottom 20px').parsesAs('left 30px bottom 20px');
+expect('top 10px left 20px').parsesAs('left 20px top 10px');
+expect('top 40px right 15%').parsesAs('right 15% top 40px');
+
 expect('left right').isInvalid();
 expect('top bottom').isInvalid();
 expect('none').isInvalid();
diff --git a/third_party/WebKit/LayoutTests/transforms/transform-origin-parsing.html b/third_party/WebKit/LayoutTests/transforms/transform-origin-parsing.html
index 39018d2e..ce31753 100644
--- a/third_party/WebKit/LayoutTests/transforms/transform-origin-parsing.html
+++ b/third_party/WebKit/LayoutTests/transforms/transform-origin-parsing.html
@@ -9,14 +9,14 @@
 expect('initial').parsesAs('initial').isComputedTo('100px 50px');
 expect('inherit').parsesAs('inherit');
 
-expect('left').parsesAs('left 50% 0px').isComputedTo('0px 50px');
-expect('center').parsesAs('center 50% 0px').isComputedTo('100px 50px');
-expect('right').parsesAs('right 50% 0px').isComputedTo('200px 50px');
-expect('top').parsesAs('50% top 0px');
-expect('bottom').parsesAs('50% bottom 0px');
-expect('0').parsesAs('0px 50% 0px');
-expect('10%').parsesAs('10% 50% 0px').isComputedTo('20px 50px');
-expect('10px').parsesAs('10px 50% 0px').isComputedTo('10px 50px');
+expect('left').parsesAs('left center 0px').isComputedTo('0px 50px');
+expect('center').parsesAs('center center 0px').isComputedTo('100px 50px');
+expect('right').parsesAs('right center 0px').isComputedTo('200px 50px');
+expect('top').parsesAs('center top 0px');
+expect('bottom').parsesAs('center bottom 0px');
+expect('0').parsesAs('0px center 0px');
+expect('10%').parsesAs('10% center 0px').isComputedTo('20px 50px');
+expect('10px').parsesAs('10px center 0px').isComputedTo('10px 50px');
 
 expect('left top').parsesAs('left top 0px');
 expect('right bottom').parsesAs('right bottom 0px');
diff --git a/third_party/WebKit/LayoutTests/typedcssom/numbervalue.html b/third_party/WebKit/LayoutTests/typedcssom/numbervalue.html
new file mode 100644
index 0000000..7d6f7e9
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/typedcssom/numbervalue.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<script src="../resources/testharness.js"></script>
+<script src="../resources/testharnessreport.js"></script>
+
+<script>
+var values = [
+  {input: new NumberValue(0), cssString: '0'},
+  {input: new NumberValue(1), cssString: '1'},
+  {input: new NumberValue(-2), cssString: '-2'},
+  {input: new NumberValue(3.4), cssString: '3.4'}
+];
+
+test(function() {
+  for (var i = 0; i < values.length; ++i) {
+    assert_equals(values[i].input.cssString, values[i].cssString);
+  }
+}, "Test that the css string for NumberValue is correct.");
+
+</script>
+
+<body>
+</body>
+
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiobuffersource-late-start-expected.txt b/third_party/WebKit/LayoutTests/webaudio/audiobuffersource-late-start-expected.txt
index 808a7026..f0a8206 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audiobuffersource-late-start-expected.txt
+++ b/third_party/WebKit/LayoutTests/webaudio/audiobuffersource-late-start-expected.txt
@@ -3,6 +3,8 @@
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
 
 
+PASS The output contains all the expected values in the correct order: [0,1].
+PASS The index of value change is equal to 5504.
 PASS The rendered buffer contains non-zero values after the first sample.
 PASS successfullyParsed is true
 
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiobuffersource-late-start.html b/third_party/WebKit/LayoutTests/webaudio/audiobuffersource-late-start.html
index 0f61eca..9b2820a 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audiobuffersource-late-start.html
+++ b/third_party/WebKit/LayoutTests/webaudio/audiobuffersource-late-start.html
@@ -5,7 +5,6 @@
   <script src="../resources/js-test.js"></script>
   <script src="resources/compatibility.js"></script>
   <script src="resources/audio-testing.js"></script>
-  <script src="resources/late-start-testing.js"></script>
 </head>
 
 <body>
@@ -13,22 +12,77 @@
     description('Test the late call of start(0) of BufferSource.');
     window.jsTestIsAsync = true;
 
-    var audit = Audit.createTaskRunner();
+    var renderQuantum = 128;
 
     var sampleRate = 44100;
+    var renderDuration = 0.25;
+    var startTime = 0.5 * renderDuration;
 
-    // The long render length (30 seconds) is to make sure the |onstatechange|
-    // event gets fired to start the source, which can take quite a bit of time.
-    var renderLength = 30;
+    var audit = Audit.createTaskRunner();
 
-    var context = new OfflineAudioContext(1, sampleRate * renderLength, sampleRate);
-    var dcOffsetbuffer = createConstantBuffer(context, 1000, 1.0);
-    var source = context.createBufferSource();
-    source.buffer = dcOffsetbuffer;
+    // Calculate the index for actual start time.
+    function getStartIndex(time) {
+      var startIndex = time * sampleRate;
+      return startIndex -= (startIndex) % renderQuantum;
+    }
 
-    // Test the buffer node is rendered correctly when the start time of start() 
-    // call is in the past in terms of the context time.
-    runLateStartTest(audit, context, source);
+    // Get the index of value change.
+    function getValueChangeIndex(array, targetValue) {
+      return array.findIndex(function (element, index) {
+        if (element === targetValue)
+          return true;
+      });
+    }
+
+    audit.defineTask('test-late-start', function (done) {
+      var context = new OfflineAudioContext(1, renderDuration * sampleRate, sampleRate);
+      var dcOffsetbuffer = createConstantBuffer(context, 1, 1.0);
+      var source = context.createBufferSource();
+      source.buffer = dcOffsetbuffer;
+      source.loop = true;
+      source.connect(context.destination);
+
+      // Schedule source.start(0) at 0.01 second. The specified timing of
+      // start() call is already passed in terms of the context time. So the
+      // argument |0| will be clamped to the current context time.
+      //
+      // With the sample rate of 44100, 0.01 second is 441 samples. Rounding
+      // it down to the render quantum gives 384 samples. This is clearly larger
+      // than a single render quantum.
+      //
+      // See issue: crbug.com/462167
+      context.suspend(startTime).then(function () {
+        source.start(0);
+        context.resume();
+      });
+
+      // Start rendering and verify result: this verifies if 1) the rendered
+      // buffer contains at least one non-zero value and 2) the non-zero value is
+      // found later than the first output sample.
+      context.startRendering().then(function (buffer) {
+
+        var channelData = buffer.getChannelData(0);
+        var startIndex = getStartIndex(startTime);
+        var nonZeroValueIndex = getValueChangeIndex(channelData, 1.0);
+
+        Should('The output', channelData).containValues([0, 1]);
+        Should('The index of value change', nonZeroValueIndex)
+          .beEqualTo(startIndex);
+
+        if (nonZeroValueIndex === 0)
+          testFailed('The first sample was non-zero value. It should be zero.');
+        else
+          testPassed('The rendered buffer contains non-zero values after the first sample.');
+
+      }).then(done);
+    });
+
+    audit.defineTask('finish-test', function (done) {
+      done();
+      finishJSTest();
+    });
+
+    audit.runTasks();
 
     successfullyParsed = true;
   </script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiochannelmerger-disconnect-expected.txt b/third_party/WebKit/LayoutTests/webaudio/audiochannelmerger-disconnect-expected.txt
index ec11c7a2..99229e5 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audiochannelmerger-disconnect-expected.txt
+++ b/third_party/WebKit/LayoutTests/webaudio/audiochannelmerger-disconnect-expected.txt
@@ -5,6 +5,7 @@
 
 PASS Channel #0 contains only the constant 1.
 PASS Channel #1 contains all the expected values in the correct order: [1,0].
+PASS The index of first zero in the channel #1 is equal to 11008.
 PASS successfullyParsed is true
 
 TEST COMPLETE
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiochannelmerger-disconnect.html b/third_party/WebKit/LayoutTests/webaudio/audiochannelmerger-disconnect.html
index c100b8f..958cb12 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audiochannelmerger-disconnect.html
+++ b/third_party/WebKit/LayoutTests/webaudio/audiochannelmerger-disconnect.html
@@ -12,29 +12,27 @@
     description('Test ChannelMergerNode behavior on dynamic input change.');
     window.jsTestIsAsync = true;
 
-    var sampleRate = 44100;
-    var numberOfChannels = 2;
+    var renderQuantum = 128;
 
-    // The test needs the long render length (20 seconds) to capture the
-    // disconnection which happens after starting the rendering. 
-    var renderLength = sampleRate * 20;
+    var numberOfChannels = 2;
+    var sampleRate = 44100;
+    var renderDuration = 0.5;
+    var disconnectTime = 0.5 * renderDuration;
 
     var audit = Audit.createTaskRunner();
 
     // Task: Check if the merger outputs a silent channel when an input is
     // disconnected.
     audit.defineTask('silent-disconnect', function (done) {
-      var context = new OfflineAudioContext(
-        numberOfChannels, renderLength, sampleRate
-      );
+      var context = new OfflineAudioContext(numberOfChannels, renderDuration * sampleRate, sampleRate);
       var merger = context.createChannelMerger();
       var source1 = context.createBufferSource();
       var source2 = context.createBufferSource();
 
-      // Create and assign a mono testing buffer.
-      var bufferDCOffset = createTestingAudioBuffer(context, 1, renderLength);
-      source1.buffer = bufferDCOffset;
-      source2.buffer = bufferDCOffset;
+      // Create and assign a constant buffer.
+      var bufferDCOffset = createConstantBuffer(context, 1, 1);
+      source1.buffer = source2.buffer = bufferDCOffset;
+      source1.loop = source2.loop = true;
 
       // Connect the output of source into the 4th input of merger. The merger
       // should produce 6 channel output.
@@ -44,22 +42,31 @@
       source1.start();
       source2.start();
 
-      // When the rendering begins, disconnect |source2| as soon as possible.
-      context.onstatechange = function () {
-        if (context.state === 'running')
-          source2.disconnect();
-      };
+      // Schedule the disconnection of |source2| at the half of render duration.
+      context.suspend(disconnectTime).then(function () {
+        source2.disconnect();
+        context.resume();
+      });
 
       context.startRendering().then(function (buffer) {
-
         // The entire first channel of the output should be 1.
         Should('Channel #0', buffer.getChannelData(0)).beConstantValueOf(1);
 
-        // The second channel should contain 1, and 0 after the disconnection.
-        Should('Channel #1', buffer.getChannelData(1)).containValues([1, 0]);
+        // Calculate the first zero index in the second channel.
+        var channel1 = buffer.getChannelData(1);
+        var disconnectIndex = disconnectTime * sampleRate; 
+        disconnectIndex -= (disconnectIndex) % renderQuantum;
+        var firstZeroIndex = channel1.findIndex(function (element, index) {
+          if (element === 0)
+            return index;
+        });
 
-        done();
-      });
+        // The second channel should contain 1, and 0 after the disconnection.
+        Should('Channel #1', channel1).containValues([1, 0]);
+        Should('The index of first zero in the channel #1', firstZeroIndex)
+          .beEqualTo(disconnectIndex);
+
+      }).then(done);
     });
 
     audit.defineTask('finish', function (done) {
@@ -67,10 +74,7 @@
       done();
     });
 
-    audit.runTasks(
-      'silent-disconnect',
-      'finish'
-    );
+    audit.runTasks();
 
     successfullyParsed = true;
   </script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/audionode-disconnect-audioparam-expected.txt b/third_party/WebKit/LayoutTests/webaudio/audionode-disconnect-audioparam-expected.txt
index 9722864..d892b79e 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audionode-disconnect-audioparam-expected.txt
+++ b/third_party/WebKit/LayoutTests/webaudio/audionode-disconnect-audioparam-expected.txt
@@ -4,8 +4,11 @@
 
 
 PASS Channel #0 contains all the expected values in the correct order: [2.25,1.5].
+PASS The index of value change is equal to 11008.
 PASS Channel #0 contains all the expected values in the correct order: [3,1.5].
+PASS The index of value change in channel #0 is equal to 11008.
 PASS Channel #1 contains all the expected values in the correct order: [6,3].
+PASS The index of value change in channel #1 is equal to 11008.
 PASS gain1.disconnect(gain3.gain) threw InvalidAccessError: Failed to execute 'disconnect' on 'AudioNode': the given AudioParam is not connected..
 PASS splitter.disconnect(gain1.gain, 1) threw InvalidAccessError: Failed to execute 'disconnect' on 'AudioNode': specified destination AudioParam and node output (1) are not connected..
 PASS splitter.disconnect(gain1.gain, 2) threw IndexSizeError: Failed to execute 'disconnect' on 'AudioNode': The output index provided (2) is outside the range [0, 1]..
diff --git a/third_party/WebKit/LayoutTests/webaudio/audionode-disconnect-audioparam.html b/third_party/WebKit/LayoutTests/webaudio/audionode-disconnect-audioparam.html
index 3c9f1fb..04746db 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audionode-disconnect-audioparam.html
+++ b/third_party/WebKit/LayoutTests/webaudio/audionode-disconnect-audioparam.html
@@ -12,27 +12,44 @@
     description('Test disconnect() method on AudioParam destination.');
     window.jsTestIsAsync = true;
 
+    var renderQuantum = 128;
+
+    var sampleRate = 44100;
+    var renderDuration = 0.5;
+    var disconnectTime = 0.5 * renderDuration;
+
     var audit = Audit.createTaskRunner();
 
-    // The long render length (20 seconds) test 1 and 2 is to make sure the 
-    // |onstatechange| event gets fired to start the source, which can take
-    // quite a bit of time.
-    var testDuration = 20;
+    // Calculate the index for disconnection.
+    function getDisconnectIndex(disconnectTime) {
+      var disconnectIndex = disconnectTime * sampleRate;
+      return disconnectIndex -= (disconnectIndex) % renderQuantum;
+    }
+
+    // Get the index of value change.
+    function getValueChangeIndex(array, targetValue) {
+      return array.findIndex(function (element, index) {
+        if (element === targetValue)
+          return true;
+      });
+    }
 
     // Task 1: test disconnect(AudioParam) method.
     audit.defineTask('disconnect(AudioParam)', function (done) {
 
       // Creates a buffer source with value [1] and then connect it to two gain
-      // nodes in series. The output of the buffer source is lowered by half 
+      // nodes in series. The output of the buffer source is lowered by half
       // (* 0.5) and then connected to two |.gain| AudioParams in each gain node.
+      //
       //  (1) bufferSource => gain1 => gain2
       //  (2) bufferSource => half => gain1.gain
       //  (3) half => gain2.gain
+      //
       // This graph should produce the output of 2.25 (= 1 * 1.5 * 1.5). After
       // disconnecting (3), it should produce 1.5.
-      var context = new OfflineAudioContext(1, 44100 * testDuration, 44100);
+      var context = new OfflineAudioContext(1, renderDuration * sampleRate, sampleRate);
       var source = context.createBufferSource();
-      var buffer1ch = createTestingAudioBuffer(context, 1, 128);
+      var buffer1ch = createConstantBuffer(context, 1, 1);
       var half = context.createGain();
       var gain1 = context.createGain();
       var gain2 = context.createGain();
@@ -46,56 +63,51 @@
       gain2.connect(context.destination);
       source.connect(half);
 
-      // Connecting |half| to both |gain1.gain| and |gain2.gain| amplifies the 
+      // Connecting |half| to both |gain1.gain| and |gain2.gain| amplifies the
       // signal by 2.25 (= 1.5 * 1.5) because each gain node amplifies the signal
       // by 1.5 (= 1.0 + 0.5).
-      half.connect(gain1.gain); 
+      half.connect(gain1.gain);
       half.connect(gain2.gain);
-      
+
       source.start();
 
-      // Disconnects after the rendering starts.
-      // 
-      // FIXME: Although this guarantees that the disconnection happens after 
-      // the rendering starts, still the actual disconnection might happen after
-      // oncomplete event fired.
-      // 
-      // The 10ms delay is 1/1000 of the total render length (10,000ms). Because 
-      // OfflineAudioContext runs faster than real time, the disconnection might
-      // happen after the rendering finishes. Then lower the delay and increase 
-      // the render length to avoid the test failure.
-      context.onstatechange = function () {
-        if (context.state === 'running')
-          half.disconnect(gain2.gain);
-      };
+      // Schedule the disconnection at the half of render duration.
+      context.suspend(disconnectTime).then(function () {
+        half.disconnect(gain2.gain);
+        context.resume();
+      });
 
       context.startRendering().then(function (buffer) {
-
-        // Note that this test depends on the disconnection below to happen
-        // sometime during rendering.
+        var channelData = buffer.getChannelData(0);
+        var disconnectIndex = getDisconnectIndex(disconnectTime);
+        var valueChangeIndex = getValueChangeIndex(channelData, 1.5);
 
         // Expected values are: 1 * 1.5 * 1.5 -> 1 * 1.5 = [2.25, 1.5]
-        Should('Channel #0', buffer.getChannelData(0)).containValues([2.25, 1.5]);
-        
+        Should('Channel #0', channelData).containValues([2.25, 1.5]);
+        Should('The index of value change', valueChangeIndex)
+          .beEqualTo(disconnectIndex);
+
       }).then(done);
     });
 
     // Task 2: test disconnect(AudioParam, output) method.
     audit.defineTask('disconnect(AudioParam, output)', function (done) {
 
-      // Create a 2-channel buffer source with [1, 2] in each channel and 
+      // Create a 2-channel buffer source with [1, 2] in each channel and
       // make a serial connection through gain1 and gain 2. The make the buffer
       // source half with a gain node and connect it to a 2-output splitter.
       // Connect each output to 2 gain AudioParams respectively.
+      //
       //    (1) bufferSource => gain1 => gain2
       //    (2) bufferSource => half => splitter(2)
       //    (3) splitter#0 => gain1.gain
       //    (4) splitter#1 => gain2.gain
-      // This graph should produce 3 (= 1 * 1.5 * 2) and 6 (= 2 * 1.5 * 2) for 
+      //
+      // This graph should produce 3 (= 1 * 1.5 * 2) and 6 (= 2 * 1.5 * 2) for
       // each channel. After disconnecting (4), it should output 1.5 and 3.
-      var context = new OfflineAudioContext(2, 44100 * testDuration, 44100);
+      var context = new OfflineAudioContext(2, renderDuration * sampleRate, sampleRate);
       var source = context.createBufferSource();
-      var buffer2ch = createTestingAudioBuffer(context, 2, 128);
+      var buffer2ch = createConstantBuffer(context, 1, [1, 2]);
       var splitter = context.createChannelSplitter(2);
       var half = context.createGain();
       var gain1 = context.createGain();
@@ -109,8 +121,8 @@
       gain1.connect(gain2);
       gain2.connect(context.destination);
 
-      // |source| originally is [1, 2] but it becomes [0.5, 1] after 0.5 gain. 
-      // Each splitter's output will be applied to |gain1.gain| and |gain2.gain| 
+      // |source| originally is [1, 2] but it becomes [0.5, 1] after 0.5 gain.
+      // Each splitter's output will be applied to |gain1.gain| and |gain2.gain|
       // respectively in an additive fashion.
       source.connect(half);
       half.connect(splitter);
@@ -123,20 +135,29 @@
 
       source.start();
 
-      // Disconnect after the rendering starts. See the comment in the previous
-      // test task.
-      context.onstatechange = function () {
-        if (context.state === 'running')
-          splitter.disconnect(gain2.gain, 1);
-      };
+      // Schedule the disconnection at the half of render duration.
+      context.suspend(disconnectTime).then(function () {
+        splitter.disconnect(gain2.gain, 1);
+        context.resume();
+      });
 
       context.startRendering().then(function (buffer) {
+        var channelData0 = buffer.getChannelData(0);
+        var channelData1 = buffer.getChannelData(1);
         
+        var disconnectIndex = getDisconnectIndex(disconnectTime);
+        var valueChangeIndexCh0 = getValueChangeIndex(channelData0, 1.5);
+        var valueChangeIndexCh1 = getValueChangeIndex(channelData1, 3);
+
         // Expected values are: 1 * 1.5 * 2 -> 1 * 1.5 = [3, 1.5]
-        Should('Channel #0', buffer.getChannelData(0)).containValues([3, 1.5]);
+        Should('Channel #0', channelData0).containValues([3, 1.5]);
+        Should('The index of value change in channel #0', valueChangeIndexCh0)
+          .beEqualTo(disconnectIndex);
 
         // Expected values are: 2 * 1.5 * 2 -> 2 * 1.5 = [6, 3]
-        Should('Channel #1', buffer.getChannelData(1)).containValues([6, 3]);
+        Should('Channel #1', channelData1).containValues([6, 3]);
+        Should('The index of value change in channel #1', valueChangeIndexCh1)
+          .beEqualTo(disconnectIndex);
 
       }).then(done);
     });
@@ -149,8 +170,8 @@
       var gain2 = context.createGain();
       var gain3 = context.createGain();
 
-      // Connect a splitter to gain nodes and merger so we can test the possible 
-      // ways of disconnecting the nodes to verify that appropriate exceptions 
+      // Connect a splitter to gain nodes and merger so we can test the possible
+      // ways of disconnecting the nodes to verify that appropriate exceptions
       // are thrown.
       gain1.connect(splitter);
       splitter.connect(gain2.gain, 0);
diff --git a/third_party/WebKit/LayoutTests/webaudio/convolver-setBuffer-null-expected.txt b/third_party/WebKit/LayoutTests/webaudio/convolver-setBuffer-null-expected.txt
index 62c8d7b..7b00bc7 100644
--- a/third_party/WebKit/LayoutTests/webaudio/convolver-setBuffer-null-expected.txt
+++ b/third_party/WebKit/LayoutTests/webaudio/convolver-setBuffer-null-expected.txt
@@ -1,8 +1,8 @@
-Tests that ConvolverNode impulse response buffer can be set to 0.
+Tests that ConvolverNode impulse response buffer can be set to null.
 
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
 
-PASS ConvolverNode impulse response buffer was set to 0.
+PASS ConvolverNode impulse response buffer was set to null.
 PASS successfullyParsed is true
 
 TEST COMPLETE
diff --git a/third_party/WebKit/LayoutTests/webaudio/convolver-setBuffer-null.html b/third_party/WebKit/LayoutTests/webaudio/convolver-setBuffer-null.html
index a3803f7a..72a46e9 100644
--- a/third_party/WebKit/LayoutTests/webaudio/convolver-setBuffer-null.html
+++ b/third_party/WebKit/LayoutTests/webaudio/convolver-setBuffer-null.html
@@ -11,7 +11,7 @@
 <div id="console"></div>
 
 <script>
-description("Tests that ConvolverNode impulse response buffer can be set to 0.");
+description("Tests that ConvolverNode impulse response buffer can be set to null.");
 
 function runTest()
 {
@@ -25,8 +25,8 @@
     var context = new AudioContext();
     var conv = context.createConvolver();
 
-    conv.buffer = 0;
-    testPassed("ConvolverNode impulse response buffer was set to 0.");
+    conv.buffer = null;
+    testPassed("ConvolverNode impulse response buffer was set to null.");
 
     finishJSTest();
 }
diff --git a/third_party/WebKit/LayoutTests/webaudio/dom-exceptions-expected.txt b/third_party/WebKit/LayoutTests/webaudio/dom-exceptions-expected.txt
index f7892ccb..3aefb727 100644
--- a/third_party/WebKit/LayoutTests/webaudio/dom-exceptions-expected.txt
+++ b/third_party/WebKit/LayoutTests/webaudio/dom-exceptions-expected.txt
@@ -52,6 +52,10 @@
 PASS node.smoothingTimeConstant is not -0.1
 PASS node.smoothingTimeConstant = 1.5 threw exception IndexSizeError: Failed to set the 'smoothingTimeConstant' property on 'AnalyserNode': The smoothing value provided (1.5) is outside the range [0, 1]..
 PASS node.smoothingTimeConstant is not 1.5
+PASS node.getFloatFrequencyData(null) threw exception TypeError: Failed to execute 'getFloatFrequencyData' on 'AnalyserNode': parameter 1 is not of type 'Float32Array'..
+PASS node.getByteFrequencyData(null) threw exception TypeError: Failed to execute 'getByteFrequencyData' on 'AnalyserNode': parameter 1 is not of type 'Uint8Array'..
+PASS node.getFloatTimeDomainData(null) threw exception TypeError: Failed to execute 'getFloatTimeDomainData' on 'AnalyserNode': parameter 1 is not of type 'Float32Array'..
+PASS node.getByteTimeDomainData(null) threw exception TypeError: Failed to execute 'getByteTimeDomainData' on 'AnalyserNode': parameter 1 is not of type 'Uint8Array'..
 PASS node.getChannelData(2) threw exception IndexSizeError: Failed to execute 'getChannelData' on 'AudioBuffer': channel index (2) exceeds number of channels (1).
 PASS node.connect(null, 0, 0) threw exception TypeError: Failed to execute 'connect' on 'AudioNode': parameter 1 is not of type 'AudioNode'..
 PASS node.connect(context.destination, 100, 0) threw exception IndexSizeError: Failed to execute 'connect' on 'AudioNode': output index (100) exceeds number of outputs (1)..
@@ -66,6 +70,11 @@
 PASS node.channelInterpretation = mode did not throw exception.
 PASS Invalid channelInterpration value did not change mode
 PASS context.destination.channelCount = 99 threw IndexSizeError exception on invalid channel count.
+PASS param.setValueCurveAtTime(null, 0, 0) threw exception TypeError: Failed to execute 'setValueCurveAtTime' on 'AudioParam': parameter 1 is not of type 'Float32Array'..
+PASS node.getFrequencyResponse(new Float32Array(1), new Float32Array(1), new Float32Array(1)) did not throw exception.
+PASS node.getFrequencyResponse(null, new Float32Array(1), new Float32Array(1)) threw exception TypeError: Failed to execute 'getFrequencyResponse' on 'BiquadFilterNode': parameter 1 is not of type 'Float32Array'..
+PASS node.getFrequencyResponse(new Float32Array(1), null, new Float32Array(1)) threw exception TypeError: Failed to execute 'getFrequencyResponse' on 'BiquadFilterNode': parameter 2 is not of type 'Float32Array'..
+PASS node.getFrequencyResponse(new Float32Array(1), new Float32Array(1), null) threw exception TypeError: Failed to execute 'getFrequencyResponse' on 'BiquadFilterNode': parameter 3 is not of type 'Float32Array'..
 PASS new OfflineAudioContext(32, 100, context.sampleRate) did not throw exception.
 PASS new OfflineAudioContext(99, 100, context.sampleRate) threw exception IndexSizeError: Failed to construct 'OfflineAudioContext': The number of channels provided (99) is outside the range [0, 32]..
 PASS new OfflineAudioContext(1, 100, 1) threw exception IndexSizeError: Failed to construct 'OfflineAudioContext': The sampleRate provided (1) is outside the range [3000, 192000]..
@@ -73,6 +82,7 @@
 PASS new OfflineAudioContext(1, -88200000000000, 44100) threw exception NotSupportedError: Failed to construct 'OfflineAudioContext': OfflineAudioContext(1, 1448390656, 44100).
 PASS node.oversample = '9x' did not throw exception.
 PASS Invalid oversample value did not change node.oversample
+PASS node.curve = {} threw exception TypeError: Failed to set the 'curve' property on 'WaveShaperNode': The provided value is not of type 'Float32Array'..
 PASS node.curve = new Float32Array(1) threw exception InvalidAccessError: Failed to set the 'curve' property on 'WaveShaperNode': The curve length provided (1) is less than the minimum bound (2)..
 PASS node.curve is null
 PASS node.curve = new Float32Array(2) did not throw exception.
@@ -135,12 +145,14 @@
 PASS osc1 = context.createOscillator() did not throw exception.
 PASS osc1.start() did not throw exception.
 PASS osc1.stop() did not throw exception.
+PASS osc.setPeriodicWave(null) threw exception TypeError: Failed to execute 'setPeriodicWave' on 'OscillatorNode': parameter 1 is not of type 'PeriodicWave'..
 PASS node.gain.exponentialRampToValueAtTime(-1, 0.1) threw exception InvalidAccessError: Failed to execute 'exponentialRampToValueAtTime' on 'AudioParam': The float target value provided (-1) is outside the range [1.40130e-45, Infinity)..
 PASS node.gain.exponentialRampToValueAtTime(0, 0.1) threw exception InvalidAccessError: Failed to execute 'exponentialRampToValueAtTime' on 'AudioParam': The float target value provided (0) is outside the range [1.40130e-45, Infinity)..
 PASS node.gain.exponentialRampToValueAtTime(Math.pow(2, -149), 0.1) did not throw exception.
 PASS node.gain.exponentialRampToValueAtTime(Math.pow(2, -150), 0.1) threw exception InvalidAccessError: Failed to execute 'exponentialRampToValueAtTime' on 'AudioParam': The float target value provided (0) is outside the range [1.40130e-45, Infinity)..
 PASS oc = new OfflineAudioContext(1, 44100, 44100) did not throw exception.
 PASS conv = oc.createConvolver() did not throw exception.
+PASS conv.buffer = {} threw exception TypeError: Failed to set the 'buffer' property on 'ConvolverNode': The provided value is not of type 'AudioBuffer'..
 PASS conv.buffer = oc.createBuffer(1, 100, 22050) threw exception NotSupportedError: Failed to set the 'buffer' property on 'ConvolverNode': The buffer sample rate of 22050 does not match the context rate of 44100 Hz..
 PASS conv.buffer is null
 PASS panner.channelCount = 1 did not throw exception.
diff --git a/third_party/WebKit/LayoutTests/webaudio/dom-exceptions.html b/third_party/WebKit/LayoutTests/webaudio/dom-exceptions.html
index 4407134..1103943 100644
--- a/third_party/WebKit/LayoutTests/webaudio/dom-exceptions.html
+++ b/third_party/WebKit/LayoutTests/webaudio/dom-exceptions.html
@@ -95,6 +95,11 @@
     shouldThrowAndBeUnchanged("node.smoothingTimeConstant", "-0.1");
     shouldThrowAndBeUnchanged("node.smoothingTimeConstant", "1.5");
 
+    shouldThrow("node.getFloatFrequencyData(null)");
+    shouldThrow("node.getByteFrequencyData(null)");
+    shouldThrow("node.getFloatTimeDomainData(null)");
+    shouldThrow("node.getByteTimeDomainData(null)");
+
     // AudioBuffers
     node = context.createBuffer(1,1, context.sampleRate);
     // Invalid channel index: IndexSizeError
@@ -142,6 +147,17 @@
             testFailed("context.destination.channelCount = 99 should throw IndexSizeError exception on invalid channel count.");
     }
 
+    // AudioParams
+    param = context.createGain().gain;
+    shouldThrow("param.setValueCurveAtTime(null, 0, 0)");
+
+    // BiquadFilterNode
+    node = context.createBiquadFilter();
+    shouldNotThrow("node.getFrequencyResponse(new Float32Array(1), new Float32Array(1), new Float32Array(1))");
+    shouldThrow("node.getFrequencyResponse(null, new Float32Array(1), new Float32Array(1))");
+    shouldThrow("node.getFrequencyResponse(new Float32Array(1), null, new Float32Array(1))");
+    shouldThrow("node.getFrequencyResponse(new Float32Array(1), new Float32Array(1), null)");
+
     // Delay nodes are tested elsewhere, so don't duplicate that work here.
 
     // OfflineAudioContext
@@ -163,6 +179,7 @@
       testPassed("Invalid oversample value did not change node.oversample");
     else
       testFailed("node.oversample incorrectly changed to invalid value " + node.oversample);
+    shouldThrow("node.curve = {}");
     shouldThrow("node.curve = new Float32Array(1)");
     shouldBeNull("node.curve");
     shouldNotThrow("node.curve = new Float32Array(2)");
@@ -246,6 +263,8 @@
     shouldNotThrow("osc1.start()");
     shouldNotThrow("osc1.stop()");
 
+    shouldThrow("osc.setPeriodicWave(null)");
+
     // exponentialRampToValue should throw on non-positive target values.
     node = context.createGain();
     node.connect(context.destination);
@@ -266,10 +285,11 @@
     // HW sample rates.
     shouldNotThrow("oc = new OfflineAudioContext(1, 44100, 44100)");
     shouldNotThrow("conv = oc.createConvolver()");
+    shouldThrow("conv.buffer = {}");
     shouldThrow("conv.buffer = oc.createBuffer(1, 100, 22050)");
     // conv.buffer should be unchanged (null) because the above failed.
     shouldBeNull("conv.buffer");
-    
+
     // PannerNode channel count and mode
     panner = context.createPanner();
     // Channel count can only be set to 1 or 2.
diff --git a/third_party/WebKit/LayoutTests/webaudio/stereopannernode-no-glitch-expected.txt b/third_party/WebKit/LayoutTests/webaudio/stereopannernode-no-glitch-expected.txt
index 25ae40bf..a6c7e47 100644
--- a/third_party/WebKit/LayoutTests/webaudio/stereopannernode-no-glitch-expected.txt
+++ b/third_party/WebKit/LayoutTests/webaudio/stereopannernode-no-glitch-expected.txt
@@ -3,12 +3,12 @@
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
 
 
-PASS Transition found. (length = 15679)
+PASS Transition found between sample #2175 and #17854.
 PASS Channel #0 has no glitch above the threshold of 0.0005.
 PASS Channel #1 has no glitch above the threshold of 0.0005.
 PASS Channel #0 equals [1.156434465040231,1.1562937736154577,...] with an element-wise tolerance of 1e-7.
 PASS Channel #1 equals [0.9876883405951378,0.987710613656166,...] with an element-wise tolerance of 1e-7.
-PASS Transition found. (length = 15679)
+PASS Transition found between sample #2175 and #17854.
 PASS Channel #0 has no glitch above the threshold of 0.0005.
 PASS Channel #1 has no glitch above the threshold of 0.0005.
 PASS Channel #0 equals [0.9876883405951378,0.987710613656166,...] with an element-wise tolerance of 1e-7.
diff --git a/third_party/WebKit/LayoutTests/webaudio/stereopannernode-no-glitch.html b/third_party/WebKit/LayoutTests/webaudio/stereopannernode-no-glitch.html
index eccf740..fcb246d 100644
--- a/third_party/WebKit/LayoutTests/webaudio/stereopannernode-no-glitch.html
+++ b/third_party/WebKit/LayoutTests/webaudio/stereopannernode-no-glitch.html
@@ -12,14 +12,8 @@
     description('Test if StereoPannerNode producing glitches by crossing zero.');
     window.jsTestIsAsync = true;
 
-    var audit = Audit.createTaskRunner();
-
     var sampleRate = 44100;
-
-    // Note that this layout test requires rather large render duration because
-    // we need enough time to do something useful in the |onstatechange| event
-    // before rendering finishes.
-    var renderDuration = 20;
+    var renderDuration = 0.5;
 
     // The threshold for glitch detection. This was experimentally determined.
     var GLITCH_THRESHOLD = 0.0005;
@@ -34,6 +28,7 @@
       numberOfArrayLog: 2
     };
 
+    var audit = Audit.createTaskRunner();
 
     // Extract a transitional region from the AudioBuffer. If no transition
     // found, fail this test.
@@ -63,7 +58,7 @@
       }
       end = index;
 
-      testPassed('Transition found. (length = ' + (end - start) + ')');
+      testPassed('Transition found between sample #' + start + ' and #' + end + '.');
 
       return {
         left: chanL.subarray(start, end),
@@ -121,15 +116,15 @@
       };
     }
 
-
+    // Build audio graph and render. Change the pan parameter in the middle of
+    // rendering.
     function panAndVerify(options, done) {
-      var context = new OfflineAudioContext(2, 44100 * renderDuration, 44100);
+      var context = new OfflineAudioContext(2, renderDuration * sampleRate, sampleRate);
       var source = context.createBufferSource();
       var panner = context.createStereoPanner();
-      var stereoBuffer = createConstantBuffer(context, 128, [1.0, 1.0]);
+      var stereoBuffer = createConstantBuffer(context, renderDuration * sampleRate, [1.0, 1.0]);
 
       source.buffer = stereoBuffer;
-      source.loop = true;
 
       panner.pan.value = options.startPanValue;
 
@@ -137,10 +132,12 @@
       panner.connect(context.destination);
       source.start();
 
-      context.onstatechange = function () {
-        if (context.state === 'running')
-          panner.pan.value = options.endPanValue;
-      };
+      // Schedule the parameter transition by the setter at 1/10 of the render
+      // duration.
+      context.suspend(0.1 * renderDuration).then(function () {
+        panner.pan.value = options.endPanValue;
+        context.resume();
+      });
 
       context.startRendering().then(function (buffer) {
         var actual = extractPanningTransition(buffer);
diff --git a/third_party/WebKit/LayoutTests/webexposed/css-properties-as-js-properties-expected.txt b/third_party/WebKit/LayoutTests/webexposed/css-properties-as-js-properties-expected.txt
index 7232672..335c6f3 100644
--- a/third_party/WebKit/LayoutTests/webexposed/css-properties-as-js-properties-expected.txt
+++ b/third_party/WebKit/LayoutTests/webexposed/css-properties-as-js-properties-expected.txt
@@ -78,6 +78,7 @@
 colorInterpolationFilters
 colorRendering
 columnFill
+contain
 content
 counterIncrement
 counterReset
diff --git a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
index 117a8ad..83a5dd3 100644
--- a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
@@ -3606,6 +3606,10 @@
     setter onclose
     setter onerror
     setter onshow
+interface NumberValue : StyleValue
+    getter value
+    method constructor
+    setter value
 interface OfflineAudioCompletionEvent : Event
     getter renderedBuffer
     method constructor
diff --git a/third_party/WebKit/ManualTests/NPN_Invoke/main.c b/third_party/WebKit/ManualTests/NPN_Invoke/main.c
deleted file mode 100644
index b726b72..0000000
--- a/third_party/WebKit/ManualTests/NPN_Invoke/main.c
+++ /dev/null
@@ -1,265 +0,0 @@
-/*
- IMPORTANT:  This Apple software is supplied to you by Apple Computer, Inc. ("Apple") in
- consideration of your agreement to the following terms, and your use, installation, 
- modification or redistribution of this Apple software constitutes acceptance of these 
- terms.  If you do not agree with these terms, please do not use, install, modify or 
- redistribute this Apple software.
- 
- In consideration of your agreement to abide by the following terms, and subject to these 
- terms, Apple grants you a personal, non-exclusive license, under Apple's copyrights in
- this original Apple software (the "Apple Software"), to use, reproduce, modify and 
- redistribute the Apple Software, with or without modifications, in source and/or binary 
- forms; provided that if you redistribute the Apple Software in its entirety and without 
- modifications, you must retain this notice and the following text and disclaimers in all 
- such redistributions of the Apple Software.  Neither the name, trademarks, service marks 
- or logos of Apple Computer, Inc. may be used to endorse or promote products derived from 
- the Apple Software without specific prior written permission from Apple. Except as expressly
- stated in this notice, no other rights or licenses, express or implied, are granted by Apple
- herein, including but not limited to any patent rights that may be infringed by your 
- derivative works or by other works in which the Apple Software may be incorporated.
- 
- The Apple Software is provided by Apple on an "AS IS" basis.  APPLE MAKES NO WARRANTIES, 
- EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, 
- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS 
- USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
- 
- IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR CONSEQUENTIAL 
- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 
-          OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, 
- REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND 
- WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR 
- OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#import <WebKit/npapi.h>
-#import <WebKit/npfunctions.h>
-#import <WebKit/npruntime.h>
-
-NPNetscapeFuncs *browser;
-
-NPError NPP_New(NPMIMEType pluginType, NPP instance, uint16_t mode, int16_t argc, char* argn[], char* argv[], NPSavedData* saved);
-NPError NPP_Destroy(NPP instance, NPSavedData** save);
-NPError NPP_SetWindow(NPP instance, NPWindow* window);
-NPError NPP_NewStream(NPP instance, NPMIMEType type, NPStream* stream, NPBool seekable, uint16_t* stype);
-NPError NPP_DestroyStream(NPP instance, NPStream* stream, NPReason reason);
-int32_t NPP_WriteReady(NPP instance, NPStream* stream);
-int32_t NPP_Write(NPP instance, NPStream* stream, int32_t offset, int32_t len, void* buffer);
-void NPP_StreamAsFile(NPP instance, NPStream* stream, const char* fname);
-void NPP_Print(NPP instance, NPPrint* platformPrint);
-int16_t NPP_HandleEvent(NPP instance, void* event);
-void NPP_URLNotify(NPP instance, const char* URL, NPReason reason, void* notifyData);
-NPError NPP_GetValue(NPP instance, NPPVariable variable, void *value);
-NPError NPP_SetValue(NPP instance, NPNVariable variable, void *value);
-
-#pragma export on
-// Mach-o entry points
-NPError NP_Initialize(NPNetscapeFuncs *browserFuncs);
-NPError NP_GetEntryPoints(NPPluginFuncs *pluginFuncs);
-void NP_Shutdown(void);
-// For compatibility with CFM browsers.
-int main(NPNetscapeFuncs *browserFuncs, NPPluginFuncs *pluginFuncs, NPP_ShutdownProcPtr *shutdown);
-#pragma export off
-
-
-typedef void (* FunctionPointer) (void);
-typedef void (* TransitionVector) (void);
-static FunctionPointer functionPointerForTVector(TransitionVector);
-static TransitionVector tVectorForFunctionPointer(FunctionPointer);
-
-// Mach-o entry points
-NPError NP_Initialize(NPNetscapeFuncs* browserFuncs)
-{
-    browser = browserFuncs;
-    return NPERR_NO_ERROR;
-}
-
-NPError NP_GetEntryPoints(NPPluginFuncs* pluginFuncs)
-{
-    pluginFuncs->version = 11;
-    pluginFuncs->size = sizeof(pluginFuncs);
-    pluginFuncs->newp = NPP_New;
-    pluginFuncs->destroy = NPP_Destroy;
-    pluginFuncs->setwindow = NPP_SetWindow;
-    pluginFuncs->newstream = NPP_NewStream;
-    pluginFuncs->destroystream = NPP_DestroyStream;
-    pluginFuncs->asfile = NPP_StreamAsFile;
-    pluginFuncs->writeready = NPP_WriteReady;
-    pluginFuncs->write = (NPP_WriteProcPtr)NPP_Write;
-    pluginFuncs->print = NPP_Print;
-    pluginFuncs->event = NPP_HandleEvent;
-    pluginFuncs->urlnotify = NPP_URLNotify;
-    pluginFuncs->getvalue = NPP_GetValue;
-    pluginFuncs->setvalue = NPP_SetValue;
-    
-    return NPERR_NO_ERROR;
-}
-
-void NP_Shutdown(void)
-{
-
-}
- 
-// For compatibility with CFM browsers.
-int main(NPNetscapeFuncs *browserFuncs, NPPluginFuncs *pluginFuncs, NPP_ShutdownProcPtr *shutdown)
-{
-    browser = malloc(sizeof(NPNetscapeFuncs));
-    bzero(browser, sizeof(NPNetscapeFuncs));
-    
-    browser->size = browserFuncs->size;
-    browser->version = browserFuncs->version;
-    
-    // Since this is a mach-o plugin and the browser is CFM because it is calling main, translate
-    // our function points into TVectors so the browser can call them.
-    browser->geturl = (NPN_GetURLProcPtr)functionPointerForTVector((TransitionVector)browserFuncs->geturl);
-    browser->posturl = (NPN_PostURLProcPtr)functionPointerForTVector((TransitionVector)browserFuncs->posturl);
-    browser->requestread = (NPN_RequestReadProcPtr)functionPointerForTVector((TransitionVector)browserFuncs->requestread);
-    browser->newstream = (NPN_NewStreamProcPtr)functionPointerForTVector((TransitionVector)browserFuncs->newstream);
-    browser->write = (NPN_WriteProcPtr)functionPointerForTVector((TransitionVector)browserFuncs->write);
-    browser->destroystream = (NPN_DestroyStreamProcPtr)functionPointerForTVector((TransitionVector)browserFuncs->destroystream);
-    browser->status = (NPN_StatusProcPtr)functionPointerForTVector((TransitionVector)browserFuncs->status);
-    browser->uagent = (NPN_UserAgentProcPtr)functionPointerForTVector((TransitionVector)browserFuncs->uagent);
-    browser->memalloc = (NPN_MemAllocProcPtr)functionPointerForTVector((TransitionVector)browserFuncs->memalloc);
-    browser->memfree = (NPN_MemFreeProcPtr)functionPointerForTVector((TransitionVector)browserFuncs->memfree);
-    browser->memflush = (NPN_MemFlushProcPtr)functionPointerForTVector((TransitionVector)browserFuncs->memflush);
-    browser->reloadplugins = (NPN_ReloadPluginsProcPtr)functionPointerForTVector((TransitionVector)browserFuncs->reloadplugins);
-    browser->geturlnotify = (NPN_GetURLNotifyProcPtr)functionPointerForTVector((TransitionVector)browserFuncs->geturlnotify);
-    browser->posturlnotify = (NPN_PostURLNotifyProcPtr)functionPointerForTVector((TransitionVector)browserFuncs->posturlnotify);
-    browser->getvalue = (NPN_GetValueProcPtr)functionPointerForTVector((TransitionVector)browserFuncs->getvalue);
-    browser->setvalue = (NPN_SetValueProcPtr)functionPointerForTVector((TransitionVector)browserFuncs->setvalue);
-    browser->invalidaterect = (NPN_InvalidateRectProcPtr)functionPointerForTVector((TransitionVector)browserFuncs->invalidaterect);
-    browser->invalidateregion = (NPN_InvalidateRegionProcPtr)functionPointerForTVector((TransitionVector)browserFuncs->invalidateregion);
-    browser->forceredraw = (NPN_ForceRedrawProcPtr)functionPointerForTVector((TransitionVector)browserFuncs->forceredraw);
-    browser->getJavaEnv = (NPN_GetJavaEnvProcPtr)functionPointerForTVector((TransitionVector)browserFuncs->getJavaEnv);
-    browser->getJavaPeer = (NPN_GetJavaPeerProcPtr)functionPointerForTVector((TransitionVector)browserFuncs->getJavaPeer);
-    
-    pluginFuncs->version = 11;
-    pluginFuncs->size = sizeof(pluginFuncs);
-    pluginFuncs->newp = (NPP_NewProcPtr)tVectorForFunctionPointer((FunctionPointer)NPP_New);
-    pluginFuncs->destroy = (NPP_DestroyProcPtr)tVectorForFunctionPointer((FunctionPointer)NPP_Destroy);
-    pluginFuncs->setwindow = (NPP_SetWindowProcPtr)tVectorForFunctionPointer((FunctionPointer)NPP_SetWindow);
-    pluginFuncs->newstream = (NPP_NewStreamProcPtr)tVectorForFunctionPointer((FunctionPointer)NPP_NewStream);
-    pluginFuncs->destroystream = (NPP_DestroyStreamProcPtr)tVectorForFunctionPointer((FunctionPointer)NPP_DestroyStream);
-    pluginFuncs->asfile = (NPP_StreamAsFileProcPtr)tVectorForFunctionPointer((FunctionPointer)NPP_StreamAsFile);
-    pluginFuncs->writeready = (NPP_WriteReadyProcPtr)tVectorForFunctionPointer((FunctionPointer)NPP_WriteReady);
-    pluginFuncs->write = (NPP_WriteProcPtr)tVectorForFunctionPointer((FunctionPointer)NPP_Write);
-    pluginFuncs->print = (NPP_PrintProcPtr)tVectorForFunctionPointer((FunctionPointer)NPP_Print);
-    pluginFuncs->event = (NPP_HandleEventProcPtr)tVectorForFunctionPointer((FunctionPointer)NPP_HandleEvent);
-    pluginFuncs->urlnotify = (NPP_URLNotifyProcPtr)tVectorForFunctionPointer((FunctionPointer)NPP_URLNotify);
-    pluginFuncs->getvalue = (NPP_GetValueProcPtr)tVectorForFunctionPointer((FunctionPointer)NPP_GetValue);
-    pluginFuncs->setvalue = (NPP_SetValueProcPtr)tVectorForFunctionPointer((FunctionPointer)NPP_SetValue);
-    
-    *shutdown = (NPP_ShutdownProcPtr)tVectorForFunctionPointer((FunctionPointer)NP_Shutdown);
-    
-    return NPERR_NO_ERROR;
-}
-
-NPError NPP_New(NPMIMEType pluginType, NPP instance, uint16_t mode, int16_t argc, char* argn[], char* argv[], NPSavedData* saved)
-{
-    // Call window.alert("Success!")
-    NPError error;
-    NPObject *windowObject = NULL;
-    error = browser->getvalue(instance, NPNVWindowNPObject, &windowObject);
-    if (error == NPERR_NO_ERROR) {
-        NPVariant alertMessage;
-        STRINGZ_TO_NPVARIANT("Success!", alertMessage);
-        NPVariant result;
-        browser->invoke(instance, windowObject, browser->getstringidentifier("alert"), &alertMessage, 1, &result);
-        browser->releaseobject(windowObject);
-    }
-    
-    return NPERR_NO_ERROR;
-}
-
-NPError NPP_Destroy(NPP instance, NPSavedData** save)
-{
-    return NPERR_NO_ERROR;
-}
-
-NPError NPP_SetWindow(NPP instance, NPWindow* window)
-{
-    return NPERR_NO_ERROR;
-}
-
-NPError NPP_NewStream(NPP instance, NPMIMEType type, NPStream* stream, NPBool seekable, uint16_t* stype)
-{
-    *stype = NP_ASFILEONLY;
-    return NPERR_NO_ERROR;
-}
-
-NPError NPP_DestroyStream(NPP instance, NPStream* stream, NPReason reason)
-{
-    return NPERR_NO_ERROR;
-}
-
-int32_t NPP_WriteReady(NPP instance, NPStream* stream)
-{
-    return 0;
-}
-
-int32_t NPP_Write(NPP instance, NPStream* stream, int32_t offset, int32_t len, void* buffer)
-{
-    return 0;
-}
-
-void NPP_StreamAsFile(NPP instance, NPStream* stream, const char* fname)
-{
-}
-
-void NPP_Print(NPP instance, NPPrint* platformPrint)
-{
-
-}
-
-int16_t NPP_HandleEvent(NPP instance, void* event)
-{
-    return 1;
-}
-
-void NPP_URLNotify(NPP instance, const char* url, NPReason reason, void* notifyData)
-{
-
-}
-
-NPError NPP_GetValue(NPP instance, NPPVariable variable, void *value)
-{
-    return NPERR_GENERIC_ERROR;
-}
-
-NPError NPP_SetValue(NPP instance, NPNVariable variable, void *value)
-{
-    return NPERR_GENERIC_ERROR;
-}
-
-// function pointer converters
-
-FunctionPointer functionPointerForTVector(TransitionVector tvp)
-{
-    const uint32_t temp[6] = {0x3D800000, 0x618C0000, 0x800C0000, 0x804C0004, 0x7C0903A6, 0x4E800420};
-    uint32_t *newGlue = NULL;
-    
-    if (tvp != NULL) {
-        newGlue = (uint32_t *)malloc(sizeof(temp));
-        if (newGlue != NULL) {
-            unsigned i;
-            for (i = 0; i < 6; i++) newGlue[i] = temp[i];
-            newGlue[0] |= ((UInt32)tvp >> 16);
-            newGlue[1] |= ((UInt32)tvp & 0xFFFF);
-            MakeDataExecutable(newGlue, sizeof(temp));
-        }
-    }
-    
-    return (FunctionPointer)newGlue;
-}
-
-TransitionVector tVectorForFunctionPointer(FunctionPointer fp)
-{
-    FunctionPointer *newGlue = NULL;
-    if (fp != NULL) {
-        newGlue = (FunctionPointer *)malloc(2 * sizeof(FunctionPointer));
-        if (newGlue != NULL) {
-            newGlue[0] = fp;
-            newGlue[1] = NULL;
-        }
-    }
-    return (TransitionVector)newGlue;
-}
diff --git a/third_party/WebKit/ManualTests/NPN_Invoke/test.html b/third_party/WebKit/ManualTests/NPN_Invoke/test.html
deleted file mode 100644
index 516470154..0000000
--- a/third_party/WebKit/ManualTests/NPN_Invoke/test.html
+++ /dev/null
@@ -1,29 +0,0 @@
-<html>
-<head>
-<title>NPN_Invoke() test</title>
-</head>
-<body>
-
-<object width="0" height="0" type="test/npn-invoke">
-  <!-- Fallback content to describe how to run the test -- />
-  <p>You do not have the &quot;NPN_Invoke&quot; plugin installed.  Before you run this test:</p>
-  <ol>
-    <li>Build the included Xcode project, &quot;NPN_Invoke.xcodeproj&quot;.</li>
-    <li>Copy the built plugin (NPN_Invoke.plugin) to /Library/Internet Plug-Ins.</li>
-    <li>Restart Safari.</li>
-  </ol>
-</object>
-
-<p>This tests NPN_Invoke(), part of the Netscape Plugin API scripting interface.</p>
-<p>To verify, you must run this test with JavaScript enabled and then repeat the test with JavaScript disabled.</p>
-
-<h4>JavaScript enabled</h4>
-<p style="color: green">Success: An alert dialog is shown with the message &quot;Success!&quot;</p>
-<p style="color: red">Failure: No alert dialog is shown, or the message is not &quot;Success!&quot;</p>
-
-<h4>JavaScript disabled</h4>
-<p style="color: green">Success: No alert dialog is shown, and Safari remains open (does not crash).</p>
-<p style="color: red">Failure: An alert dialog is shown, or Safari crashes.</p>
-
-</body>
-</html>
diff --git a/third_party/WebKit/Source/BUILD.gn b/third_party/WebKit/Source/BUILD.gn
index da14ddd..14e4d9f 100644
--- a/third_party/WebKit/Source/BUILD.gn
+++ b/third_party/WebKit/Source/BUILD.gn
@@ -30,6 +30,7 @@
   include_dirs = [
     ".",
     "..",
+    "$root_gen_dir/blink",
   ]
 
   cflags = []
diff --git a/third_party/WebKit/Source/bindings/core/v8/ScriptState.h b/third_party/WebKit/Source/bindings/core/v8/ScriptState.h
index 85d7830..e093755d 100644
--- a/third_party/WebKit/Source/bindings/core/v8/ScriptState.h
+++ b/third_party/WebKit/Source/bindings/core/v8/ScriptState.h
@@ -65,7 +65,7 @@
         v8::Local<v8::Context> context = isolate->GetCurrentContext();
         if (context.IsEmpty())
             return false;
-        return context != v8::Debug::GetDebugContext();
+        return context != v8::Debug::GetDebugContext(isolate);
     }
 
     static ScriptState* from(v8::Local<v8::Context> context)
diff --git a/third_party/WebKit/Source/core/core.gypi b/third_party/WebKit/Source/core/core.gypi
index 0b32d3f..57d5cc942 100644
--- a/third_party/WebKit/Source/core/core.gypi
+++ b/third_party/WebKit/Source/core/core.gypi
@@ -41,6 +41,7 @@
             'css/StyleSheetList.idl',
             'css/WebKitCSSMatrix.idl',
             'css/cssom/KeywordValue.idl',
+            'css/cssom/NumberValue.idl',
             'css/cssom/StyleValue.idl',
             'dom/ArrayBuffer.idl',
             'dom/ArrayBufferView.idl',
@@ -1231,6 +1232,7 @@
             'css/StyleSheetList.h',
             'css/cssom/KeywordValue.cpp',
             'css/cssom/KeywordValue.h',
+            'css/cssom/NumberValue.h',
             'css/cssom/StyleValue.cpp',
             'css/cssom/StyleValue.h',
             'css/invalidation/InvalidationSet.cpp',
@@ -3917,6 +3919,7 @@
             'loader/LinkHeaderTest.cpp',
             'loader/LinkLoaderTest.cpp',
             'loader/MixedContentCheckerTest.cpp',
+            'page/ChromeClientTest.cpp',
             'page/ContextMenuControllerTest.cpp',
             'page/NetworkStateNotifierTest.cpp',
             'page/PagePopupClientTest.cpp',
diff --git a/third_party/WebKit/Source/core/css/CSSPrimitiveValueMappings.h b/third_party/WebKit/Source/core/css/CSSPrimitiveValueMappings.h
index a10c3c2..5f261fc 100644
--- a/third_party/WebKit/Source/core/css/CSSPrimitiveValueMappings.h
+++ b/third_party/WebKit/Source/core/css/CSSPrimitiveValueMappings.h
@@ -4595,6 +4595,49 @@
     return ScrollSnapTypeNone;
 }
 
+template<> inline CSSPrimitiveValue::CSSPrimitiveValue(Containment snapType)
+    : CSSValue(PrimitiveClass)
+{
+    init(UnitType::ValueID);
+    switch (snapType) {
+    case ContainsNone:
+        m_value.valueID = CSSValueNone;
+        break;
+    case ContainsStrict:
+        m_value.valueID = CSSValueStrict;
+        break;
+    case ContainsPaint:
+        m_value.valueID = CSSValuePaint;
+        break;
+    case ContainsStyle:
+        m_value.valueID = CSSValueStyle;
+        break;
+    case ContainsLayout:
+        m_value.valueID = CSSValueLayout;
+        break;
+    }
+}
+
+template<> inline Containment CSSPrimitiveValue::convertTo() const
+{
+    switch (getValueID()) {
+    case CSSValueNone:
+        return ContainsNone;
+    case CSSValueStrict:
+        return ContainsStrict;
+    case CSSValuePaint:
+        return ContainsPaint;
+    case CSSValueStyle:
+        return ContainsStyle;
+    case CSSValueLayout:
+        return ContainsLayout;
+    default:
+        break;
+    }
+    ASSERT_NOT_REACHED();
+    return ContainsNone;
+}
+
 } // namespace blink
 
 #endif
diff --git a/third_party/WebKit/Source/core/css/CSSProperties.in b/third_party/WebKit/Source/core/css/CSSProperties.in
index 6d4d2133..fd18ed9 100644
--- a/third_party/WebKit/Source/core/css/CSSProperties.in
+++ b/third_party/WebKit/Source/core/css/CSSProperties.in
@@ -163,6 +163,7 @@
 color-interpolation-filters inherited, svg, type_name=EColorInterpolation
 color-rendering inherited, svg
 column-fill runtime_flag=ColumnFill, type_name=ColumnFill
+contain runtime_flag=CSSContainment, converter=convertFlags<Containment>
 content custom_all
 counter-increment custom_all
 counter-reset custom_all
@@ -249,7 +250,7 @@
 page-break-inside type_name=EPageBreak, initial=initialPageBreak
 paint-order inherited, svg, converter=convertPaintOrder
 perspective interpolable, converter=convertPerspective
-perspective-origin interpolable, converter=convertPerspectiveOrigin
+perspective-origin interpolable, converter=convertPosition
 pointer-events inherited
 position
 quotes inherited, converter=convertQuotes
@@ -447,7 +448,7 @@
 background longhands=background-image;background-position-x;background-position-y;background-size;background-repeat-x;background-repeat-y;background-attachment;background-origin;background-clip;background-color
 background-position longhands=background-position-x;background-position-y
 background-repeat longhands=background-repeat-x;background-repeat-y
-border longhands=border-top-color;border-top-style;border-top-width;border-right-color;border-right-style;border-right-width;border-bottom-color;border-bottom-style;border-bottom-width;border-left-color;border-left-style;border-left-width
+border longhands=border-top-color;border-top-style;border-top-width;border-right-color;border-right-style;border-right-width;border-bottom-color;border-bottom-style;border-bottom-width;border-left-color;border-left-style;border-left-width;border-image-source;border-image-slice;border-image-width;border-image-outset;border-image-repeat
 border-bottom longhands=border-bottom-width;border-bottom-style;border-bottom-color
 border-color longhands=border-top-color;border-right-color;border-bottom-color;border-left-color
 border-image longhands=border-image-source;border-image-slice;border-image-width;border-image-outset;border-image-repeat
diff --git a/third_party/WebKit/Source/core/css/CSSValueKeywords.in b/third_party/WebKit/Source/core/css/CSSValueKeywords.in
index 79ceda3..ea1e0c43 100644
--- a/third_party/WebKit/Source/core/css/CSSValueKeywords.in
+++ b/third_party/WebKit/Source/core/css/CSSValueKeywords.in
@@ -1054,5 +1054,10 @@
 proximity
 from-image
 
+// containment
+paint
+style
+layout
+
 var
 -internal-variable-value
diff --git a/third_party/WebKit/Source/core/css/ComputedStyleCSSValueMapping.cpp b/third_party/WebKit/Source/core/css/ComputedStyleCSSValueMapping.cpp
index 2b4ff3a..27e94c1 100644
--- a/third_party/WebKit/Source/core/css/ComputedStyleCSSValueMapping.cpp
+++ b/third_party/WebKit/Source/core/css/ComputedStyleCSSValueMapping.cpp
@@ -2679,6 +2679,22 @@
             list->append(cssValuePool().createValue(style.scale()->z(), CSSPrimitiveValue::UnitType::Number));
         return list.release();
     }
+    case CSSPropertyContain: {
+        if (!style.contain())
+            return cssValuePool().createIdentifierValue(CSSValueNone);
+        if (style.contain() == ContainsStrict)
+            return cssValuePool().createIdentifierValue(CSSValueStrict);
+
+        RefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
+        if (style.contain() & ContainsStyle)
+            list->append(cssValuePool().createIdentifierValue(CSSValueStyle));
+        if (style.contain() & ContainsLayout)
+            list->append(cssValuePool().createIdentifierValue(CSSValueLayout));
+        if (style.contain() & ContainsPaint)
+            list->append(cssValuePool().createIdentifierValue(CSSValuePaint));
+        ASSERT(list->length());
+        return list.release();
+    }
     case CSSPropertyVariable:
         // TODO(leviw): We should have a way to retrive variables here.
         ASSERT_NOT_REACHED();
diff --git a/third_party/WebKit/Source/core/css/MediaQueryEvaluator.cpp b/third_party/WebKit/Source/core/css/MediaQueryEvaluator.cpp
index b2c7a68..161fece 100644
--- a/third_party/WebKit/Source/core/css/MediaQueryEvaluator.cpp
+++ b/third_party/WebKit/Source/core/css/MediaQueryEvaluator.cpp
@@ -393,7 +393,7 @@
 
 static bool heightMediaFeatureEval(const MediaQueryExpValue& value, MediaFeaturePrefix op, const MediaValues& mediaValues)
 {
-    int height = mediaValues.viewportHeight();
+    double height = mediaValues.viewportHeight();
     if (value.isValid())
         return computeLengthAndCompare(value, op, mediaValues, height);
 
@@ -402,7 +402,7 @@
 
 static bool widthMediaFeatureEval(const MediaQueryExpValue& value, MediaFeaturePrefix op, const MediaValues& mediaValues)
 {
-    int width = mediaValues.viewportWidth();
+    double width = mediaValues.viewportWidth();
     if (value.isValid())
         return computeLengthAndCompare(value, op, mediaValues, width);
 
diff --git a/third_party/WebKit/Source/core/css/MediaQueryEvaluatorTest.cpp b/third_party/WebKit/Source/core/css/MediaQueryEvaluatorTest.cpp
index 6770c7e4..25ee2ce 100644
--- a/third_party/WebKit/Source/core/css/MediaQueryEvaluatorTest.cpp
+++ b/third_party/WebKit/Source/core/css/MediaQueryEvaluatorTest.cpp
@@ -92,6 +92,30 @@
     {0, 0} // Do not remove the terminator line.
 };
 
+TestCase floatViewportTestCases[] = {
+    {"all and (min-width: 600.5px)", 1},
+    {"(min-width: 600px)", 1},
+    {"(min-width: 600.5px)", 1},
+    {"(min-width: 601px)", 0},
+    {"(max-width: 600px)", 0},
+    {"(max-width: 600.5px)", 1},
+    {"(max-width: 601px)", 1},
+    {"(width: 600.5px)", 1},
+    {"(width: 601px)", 0},
+    {"(min-height: 700px)", 1},
+    {"(min-height: 700.125px)", 1},
+    {"(min-height: 701px)", 0},
+    {"(min-height: 700.126px)", 0},
+    {"(max-height: 701px)", 1},
+    {"(max-height: 700.125px)", 1},
+    {"(max-height: 700px)", 0},
+    {"(height: 700.125px)", 1},
+    {"(height: 700.126px)", 0},
+    {"(height: 700.124px)", 0},
+    {"(height: 701px)", 0},
+    {0, 0} // Do not remove the terminator line.
+};
+
 TestCase printTestCases[] = {
     {"print and (min-resolution: 1dppx)", 1},
     {"print and (min-resolution: 118dpcm)", 1},
@@ -159,4 +183,15 @@
     EXPECT_FALSE(mediaQueryEvaluator.eval(querySet.get()));
 }
 
+TEST(MediaQueryEvaluatorTest, CachedFloatViewport)
+{
+    MediaValuesCached::MediaValuesCachedData data;
+    data.viewportWidth = 600.5;
+    data.viewportHeight = 700.125;
+    RefPtrWillBeRawPtr<MediaValues> mediaValues = MediaValuesCached::create(data);
+
+    MediaQueryEvaluator mediaQueryEvaluator(*mediaValues);
+    testMQEvaluator(floatViewportTestCases, mediaQueryEvaluator);
+}
+
 } // namespace
diff --git a/third_party/WebKit/Source/core/css/MediaValues.cpp b/third_party/WebKit/Source/core/css/MediaValues.cpp
index 294df98..a36c341 100644
--- a/third_party/WebKit/Source/core/css/MediaValues.cpp
+++ b/third_party/WebKit/Source/core/css/MediaValues.cpp
@@ -32,18 +32,18 @@
     return MediaValuesCached::create();
 }
 
-int MediaValues::calculateViewportWidth(LocalFrame* frame) const
+double MediaValues::calculateViewportWidth(LocalFrame* frame) const
 {
     ASSERT(frame && frame->view() && frame->document());
     int viewportWidth = frame->view()->layoutSize(IncludeScrollbars).width();
-    return adjustForAbsoluteZoom(viewportWidth, frame->document()->layoutView());
+    return adjustDoubleForAbsoluteZoom(viewportWidth, *frame->document()->layoutView());
 }
 
-int MediaValues::calculateViewportHeight(LocalFrame* frame) const
+double MediaValues::calculateViewportHeight(LocalFrame* frame) const
 {
     ASSERT(frame && frame->view() && frame->document());
     int viewportHeight = frame->view()->layoutSize(IncludeScrollbars).height();
-    return adjustForAbsoluteZoom(viewportHeight, frame->document()->layoutView());
+    return adjustDoubleForAbsoluteZoom(viewportHeight, *frame->document()->layoutView());
 }
 
 int MediaValues::calculateDeviceWidth(LocalFrame* frame) const
@@ -153,7 +153,7 @@
     return frame->settings()->availableHoverTypes();
 }
 
-bool MediaValues::computeLengthImpl(double value, CSSPrimitiveValue::UnitType type, unsigned defaultFontSize, unsigned viewportWidth, unsigned viewportHeight, double& result)
+bool MediaValues::computeLengthImpl(double value, CSSPrimitiveValue::UnitType type, unsigned defaultFontSize, double viewportWidth, double viewportHeight, double& result)
 {
     // The logic in this function is duplicated from CSSToLengthConversionData::zoomedComputedPixels()
     // because MediaValues::computeLength() needs nearly identical logic, but we haven't found a way to make
diff --git a/third_party/WebKit/Source/core/css/MediaValues.h b/third_party/WebKit/Source/core/css/MediaValues.h
index d32c002..7ce4fdf 100644
--- a/third_party/WebKit/Source/core/css/MediaValues.h
+++ b/third_party/WebKit/Source/core/css/MediaValues.h
@@ -28,9 +28,9 @@
     virtual PassRefPtrWillBeRawPtr<MediaValues> copy() const = 0;
     virtual bool isSafeToSendToAnotherThread() const = 0;
 
-    static bool computeLengthImpl(double value, CSSPrimitiveValue::UnitType, unsigned defaultFontSize, unsigned viewportWidth, unsigned viewportHeight, double& result);
+    static bool computeLengthImpl(double value, CSSPrimitiveValue::UnitType, unsigned defaultFontSize, double viewportWidth, double viewportHeight, double& result);
     template<typename T>
-    static bool computeLength(double value, CSSPrimitiveValue::UnitType type, unsigned defaultFontSize, unsigned viewportWidth, unsigned viewportHeight, T& result)
+    static bool computeLength(double value, CSSPrimitiveValue::UnitType type, unsigned defaultFontSize, double viewportWidth, double viewportHeight, T& result)
     {
         double tempResult;
         if (!computeLengthImpl(value, type, defaultFontSize, viewportWidth, viewportHeight, tempResult))
@@ -41,8 +41,8 @@
     virtual bool computeLength(double value, CSSPrimitiveValue::UnitType, int& result) const = 0;
     virtual bool computeLength(double value, CSSPrimitiveValue::UnitType, double& result) const = 0;
 
-    virtual int viewportWidth() const = 0;
-    virtual int viewportHeight() const = 0;
+    virtual double viewportWidth() const = 0;
+    virtual double viewportHeight() const = 0;
     virtual int deviceWidth() const = 0;
     virtual int deviceHeight() const = 0;
     virtual float devicePixelRatio() const = 0;
@@ -62,8 +62,8 @@
     virtual bool isCached() const { return false; }
 
 protected:
-    int calculateViewportWidth(LocalFrame*) const;
-    int calculateViewportHeight(LocalFrame*) const;
+    double calculateViewportWidth(LocalFrame*) const;
+    double calculateViewportHeight(LocalFrame*) const;
     int calculateDeviceWidth(LocalFrame*) const;
     int calculateDeviceHeight(LocalFrame*) const;
     bool calculateStrictMode(LocalFrame*) const;
diff --git a/third_party/WebKit/Source/core/css/MediaValuesCached.cpp b/third_party/WebKit/Source/core/css/MediaValuesCached.cpp
index 3dedbd1..b4fd8efd 100644
--- a/third_party/WebKit/Source/core/css/MediaValuesCached.cpp
+++ b/third_party/WebKit/Source/core/css/MediaValuesCached.cpp
@@ -100,12 +100,12 @@
 #endif
 }
 
-int MediaValuesCached::viewportWidth() const
+double MediaValuesCached::viewportWidth() const
 {
     return m_data.viewportWidth;
 }
 
-int MediaValuesCached::viewportHeight() const
+double MediaValuesCached::viewportHeight() const
 {
     return m_data.viewportHeight;
 }
@@ -185,12 +185,12 @@
     return true;
 }
 
-void MediaValuesCached::setViewportWidth(int width)
+void MediaValuesCached::setViewportWidth(double width)
 {
     m_data.viewportWidth = width;
 }
 
-void MediaValuesCached::setViewportHeight(int height)
+void MediaValuesCached::setViewportHeight(double height)
 {
     m_data.viewportHeight = height;
 }
diff --git a/third_party/WebKit/Source/core/css/MediaValuesCached.h b/third_party/WebKit/Source/core/css/MediaValuesCached.h
index 5f5331e..3bd3f62 100644
--- a/third_party/WebKit/Source/core/css/MediaValuesCached.h
+++ b/third_party/WebKit/Source/core/css/MediaValuesCached.h
@@ -15,8 +15,8 @@
     struct MediaValuesCachedData {
         DISALLOW_NEW();
         // Members variables must be thread safe, since they're copied to the parser thread
-        int viewportWidth;
-        int viewportHeight;
+        double viewportWidth;
+        double viewportHeight;
         int deviceWidth;
         int deviceHeight;
         float devicePixelRatio;
@@ -61,8 +61,8 @@
     bool computeLength(double value, CSSPrimitiveValue::UnitType, int& result) const override;
     bool computeLength(double value, CSSPrimitiveValue::UnitType, double& result) const override;
 
-    int viewportWidth() const override;
-    int viewportHeight() const override;
+    double viewportWidth() const override;
+    double viewportHeight() const override;
     int deviceWidth() const override;
     int deviceHeight() const override;
     float devicePixelRatio() const override;
@@ -79,8 +79,8 @@
     const String mediaType() const override;
     WebDisplayMode displayMode() const override;
 
-    void setViewportWidth(int);
-    void setViewportHeight(int);
+    void setViewportWidth(double);
+    void setViewportHeight(double);
 
     bool isCached() const override { return true; }
 protected:
diff --git a/third_party/WebKit/Source/core/css/MediaValuesDynamic.cpp b/third_party/WebKit/Source/core/css/MediaValuesDynamic.cpp
index a222f9d..eaf80b50 100644
--- a/third_party/WebKit/Source/core/css/MediaValuesDynamic.cpp
+++ b/third_party/WebKit/Source/core/css/MediaValuesDynamic.cpp
@@ -62,12 +62,12 @@
     return false;
 }
 
-int MediaValuesDynamic::viewportWidth() const
+double MediaValuesDynamic::viewportWidth() const
 {
     return calculateViewportWidth(m_frame);
 }
 
-int MediaValuesDynamic::viewportHeight() const
+double MediaValuesDynamic::viewportHeight() const
 {
     return calculateViewportHeight(m_frame);
 }
diff --git a/third_party/WebKit/Source/core/css/MediaValuesDynamic.h b/third_party/WebKit/Source/core/css/MediaValuesDynamic.h
index 6a1731c9..e6698d27 100644
--- a/third_party/WebKit/Source/core/css/MediaValuesDynamic.h
+++ b/third_party/WebKit/Source/core/css/MediaValuesDynamic.h
@@ -20,8 +20,8 @@
     bool computeLength(double value, CSSPrimitiveValue::UnitType, int& result) const override;
     bool computeLength(double value, CSSPrimitiveValue::UnitType, double& result) const override;
 
-    int viewportWidth() const override;
-    int viewportHeight() const override;
+    double viewportWidth() const override;
+    double viewportHeight() const override;
     int deviceWidth() const override;
     int deviceHeight() const override;
     float devicePixelRatio() const override;
diff --git a/third_party/WebKit/Source/core/css/cssom/KeywordValue.cpp b/third_party/WebKit/Source/core/css/cssom/KeywordValue.cpp
index 1022150..41f9c6e 100644
--- a/third_party/WebKit/Source/core/css/cssom/KeywordValue.cpp
+++ b/third_party/WebKit/Source/core/css/cssom/KeywordValue.cpp
@@ -49,7 +49,7 @@
     }
 }
 
-const String& KeywordValue::cssString() const
+String KeywordValue::cssString() const
 {
     return keywordValue();
 }
diff --git a/third_party/WebKit/Source/core/css/cssom/KeywordValue.h b/third_party/WebKit/Source/core/css/cssom/KeywordValue.h
index 6bdb0a77..5816fe37 100644
--- a/third_party/WebKit/Source/core/css/cssom/KeywordValue.h
+++ b/third_party/WebKit/Source/core/css/cssom/KeywordValue.h
@@ -23,7 +23,7 @@
 
     virtual const String& keywordValue() const;
 
-    const String& cssString() const override;
+    String cssString() const override;
     PassRefPtrWillBeRawPtr<CSSValue> toCSSValue() override;
 
 protected:
diff --git a/third_party/WebKit/Source/core/css/cssom/NumberValue.h b/third_party/WebKit/Source/core/css/cssom/NumberValue.h
new file mode 100644
index 0000000..ed4bfc2
--- /dev/null
+++ b/third_party/WebKit/Source/core/css/cssom/NumberValue.h
@@ -0,0 +1,43 @@
+#ifndef NumberValue_h
+#define NumberValue_h
+
+#include "bindings/core/v8/ScriptWrappable.h"
+#include "core/CoreExport.h"
+#include "core/css/CSSPrimitiveValue.h"
+#include "core/css/cssom/StyleValue.h"
+#include "wtf/text/WTFString.h"
+
+namespace blink {
+
+class CORE_EXPORT NumberValue final : public StyleValue {
+    DEFINE_WRAPPERTYPEINFO();
+public:
+    static PassRefPtrWillBeRawPtr<NumberValue> create(double value)
+    {
+        return adoptRefWillBeNoop(new NumberValue(value));
+    }
+
+    double value() const { return m_value; }
+    void setValue(double value)
+    {
+        m_value = value;
+    }
+
+    String cssString() const override { return String::number(m_value); }
+
+    PassRefPtrWillBeRawPtr<CSSValue> toCSSValue() override
+    {
+        return cssValuePool().createValue(m_value, CSSPrimitiveValue::UnitType::
+Number);
+    }
+
+    StyleValueType type() const override { return StyleValueType::NumberType; }
+protected:
+    NumberValue(double value) : m_value(value) {}
+
+    double m_value;
+};
+
+} // namespace blink
+
+#endif
diff --git a/third_party/WebKit/Source/core/css/cssom/NumberValue.idl b/third_party/WebKit/Source/core/css/cssom/NumberValue.idl
new file mode 100644
index 0000000..7080174
--- /dev/null
+++ b/third_party/WebKit/Source/core/css/cssom/NumberValue.idl
@@ -0,0 +1,6 @@
+ [
+     Constructor(double value),
+     RuntimeEnabled=CSSTypedOM
+ ] interface NumberValue : StyleValue {
+   attribute double value;
+ };
diff --git a/third_party/WebKit/Source/core/css/cssom/StyleValue.h b/third_party/WebKit/Source/core/css/cssom/StyleValue.h
index 7dc1841..2b70c7c5 100644
--- a/third_party/WebKit/Source/core/css/cssom/StyleValue.h
+++ b/third_party/WebKit/Source/core/css/cssom/StyleValue.h
@@ -24,7 +24,7 @@
     static PassRefPtrWillBeRawPtr<StyleValue> create(const CSSValue&);
     static ScriptValue parse(ScriptState*, const String& property, const String& cssText);
 
-    virtual const String& cssString() const = 0;
+    virtual String cssString() const = 0;
     virtual PassRefPtrWillBeRawPtr<CSSValue> toCSSValue() = 0;
 
     DEFINE_INLINE_VIRTUAL_TRACE() { }
diff --git a/third_party/WebKit/Source/core/css/invalidation/InvalidationSet.cpp b/third_party/WebKit/Source/core/css/invalidation/InvalidationSet.cpp
index 180c313..1eff1df 100644
--- a/third_party/WebKit/Source/core/css/invalidation/InvalidationSet.cpp
+++ b/third_party/WebKit/Source/core/css/invalidation/InvalidationSet.cpp
@@ -51,8 +51,9 @@
     s_tracingEnabled = TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(TRACE_DISABLED_BY_DEFAULT("devtools.timeline.invalidationTracking"));
 }
 
-InvalidationSet::InvalidationSet()
-    : m_allDescendantsMightBeInvalid(false)
+InvalidationSet::InvalidationSet(InvalidationType type)
+    : m_type(type)
+    , m_allDescendantsMightBeInvalid(false)
     , m_invalidatesSelf(false)
     , m_customPseudoInvalid(false)
     , m_treeBoundaryCrossing(false)
@@ -99,6 +100,8 @@
 
 void InvalidationSet::combine(const InvalidationSet& other)
 {
+    ASSERT(m_type == other.m_type);
+
     // No longer bother combining data structures, since the whole subtree is deemed invalid.
     if (wholeSubtreeInvalid())
         return;
@@ -141,6 +144,14 @@
     }
 }
 
+void InvalidationSet::destroy()
+{
+    if (isDescendantInvalidationSet())
+        delete toDescendantInvalidationSet(this);
+    else
+        delete toSiblingInvalidationSet(this);
+}
+
 HashSet<AtomicString>& InvalidationSet::ensureClassSet()
 {
     if (!m_classes)
@@ -270,7 +281,8 @@
 #endif // NDEBUG
 
 SiblingInvalidationSet::SiblingInvalidationSet()
-    : m_maxDirectAdjacentSelectors(1)
+    : InvalidationSet(InvalidateSiblings)
+    , m_maxDirectAdjacentSelectors(1)
     , m_descendantInvalidationSet(DescendantInvalidationSet::create())
 {
 }
diff --git a/third_party/WebKit/Source/core/css/invalidation/InvalidationSet.h b/third_party/WebKit/Source/core/css/invalidation/InvalidationSet.h
index 3a922578..f6010ee4 100644
--- a/third_party/WebKit/Source/core/css/invalidation/InvalidationSet.h
+++ b/third_party/WebKit/Source/core/css/invalidation/InvalidationSet.h
@@ -58,10 +58,8 @@
     WTF_MAKE_NONCOPYABLE(InvalidationSet);
     USING_FAST_MALLOC_WITH_TYPE_NAME(blink::InvalidationSet);
 public:
-    virtual ~InvalidationSet() {}
-
-    virtual bool isDescendantInvalidationSet() const { return false; }
-    virtual bool isSiblingInvalidationSet() const { return false; }
+    bool isDescendantInvalidationSet() const { return m_type == InvalidateDescendants; }
+    bool isSiblingInvalidationSet() const { return m_type == InvalidateSiblings; }
 
     static void cacheTracingFlag();
 
@@ -100,12 +98,21 @@
     const HashSet<AtomicString>& tagNameSetForTesting() const { ASSERT(m_tagNames); return *m_tagNames; }
     const HashSet<AtomicString>& attributeSetForTesting() const { ASSERT(m_attributes); return *m_attributes; }
 
+    void deref()
+    {
+        if (!derefBase())
+            return;
+        destroy();
+    }
+
 protected:
-    InvalidationSet();
+    InvalidationSet(InvalidationType);
 
     void combine(const InvalidationSet& other);
 
 private:
+    void destroy();
+
     HashSet<AtomicString>& ensureClassSet();
     HashSet<AtomicString>& ensureIdSet();
     HashSet<AtomicString>& ensureTagNameSet();
@@ -117,6 +124,8 @@
     OwnPtr<HashSet<AtomicString>> m_tagNames;
     OwnPtr<HashSet<AtomicString>> m_attributes;
 
+    unsigned m_type : 1;
+
     // If true, all descendants might be invalidated, so a full subtree recalc is required.
     unsigned m_allDescendantsMightBeInvalid : 1;
 
@@ -140,15 +149,14 @@
         return adoptRef(new DescendantInvalidationSet);
     }
 
-    bool isDescendantInvalidationSet() const final { return true; }
-
     void combine(const DescendantInvalidationSet& other)
     {
         InvalidationSet::combine(other);
     }
 
 private:
-    DescendantInvalidationSet() {}
+    DescendantInvalidationSet()
+        : InvalidationSet(InvalidateDescendants) {}
 };
 
 class CORE_EXPORT SiblingInvalidationSet final : public InvalidationSet {
@@ -158,8 +166,6 @@
         return adoptRef(new SiblingInvalidationSet);
     }
 
-    bool isSiblingInvalidationSet() const final { return true; }
-
     void combine(const SiblingInvalidationSet& other);
 
     DescendantInvalidationSet& descendants() { return *m_descendantInvalidationSet; }
diff --git a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp
index f7d85192..671cabf 100644
--- a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp
+++ b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp
@@ -602,21 +602,6 @@
     return consumeLengthOrPercent(range, cssParserMode, ValueRangeAll, unitless);
 }
 
-static PassRefPtrWillBeRawPtr<CSSPrimitiveValue> resolvePositionComponentKeywords(PassRefPtrWillBeRawPtr<CSSPrimitiveValue> value)
-{
-    if (!value->isValueID())
-        return value;
-    CSSValueID id = value->getValueID();
-    int percent = 0;
-    if (id == CSSValueCenter)
-        percent = 50;
-    else if (id == CSSValueBottom || id == CSSValueRight)
-        percent = 100;
-    else
-        ASSERT(id == CSSValueLeft || id == CSSValueTop);
-    return cssValuePool().createValue(percent, CSSPrimitiveValue::UnitType::Percentage);
-}
-
 static bool isHorizontalPositionKeywordOnly(const CSSPrimitiveValue& value)
 {
     return value.isValueID() && (value.getValueID() == CSSValueLeft || value.getValueID() == CSSValueRight);
@@ -630,8 +615,8 @@
 static void positionFromOneValue(PassRefPtrWillBeRawPtr<CSSPrimitiveValue> value, RefPtrWillBeRawPtr<CSSValue>& resultX, RefPtrWillBeRawPtr<CSSValue>& resultY)
 {
     bool valueAppliesToYAxisOnly = isVerticalPositionKeywordOnly(*value);
-    resultX = resolvePositionComponentKeywords(value);
-    resultY = cssValuePool().createValue(50, CSSPrimitiveValue::UnitType::Percentage);
+    resultX = value;
+    resultY = cssValuePool().createIdentifierValue(CSSValueCenter);
     if (valueAppliesToYAxisOnly)
         swap(resultX, resultY);
 }
@@ -644,8 +629,8 @@
     bool mustOrderAsYX = isVerticalPositionKeywordOnly(*value1) || isHorizontalPositionKeywordOnly(*value2);
     if (mustOrderAsXY && mustOrderAsYX)
         return false;
-    resultX = resolvePositionComponentKeywords(value1);
-    resultY = resolvePositionComponentKeywords(value2);
+    resultX = value1;
+    resultY = value2;
     if (mustOrderAsYX)
         swap(resultX, resultY);
     return true;
@@ -653,7 +638,7 @@
 
 static bool positionFromThreeOrFourValues(CSSPrimitiveValue** values, RefPtrWillBeRawPtr<CSSValue>& resultX, RefPtrWillBeRawPtr<CSSValue>& resultY)
 {
-    bool seenCenter = false;
+    CSSPrimitiveValue* center = nullptr;
     for (int i = 0; values[i]; i++) {
         CSSPrimitiveValue* currentValue = values[i];
         if (!currentValue->isValueID())
@@ -661,42 +646,39 @@
         CSSValueID id = currentValue->getValueID();
 
         if (id == CSSValueCenter) {
-            if (seenCenter)
+            if (center)
                 return false;
-            seenCenter = true;
+            center = currentValue;
             continue;
         }
 
-        RefPtrWillBeRawPtr<CSSPrimitiveValue> offset = nullptr;
+        RefPtrWillBeRawPtr<CSSValue> result = nullptr;
         if (values[i + 1] && !values[i + 1]->isValueID()) {
-            offset = values[++i];
+            result = CSSValuePair::create(currentValue, values[++i], CSSValuePair::KeepIdenticalValues);
         } else {
-            offset = cssValuePool().createValue(0, CSSPrimitiveValue::UnitType::Percentage);
+            result = currentValue;
         }
 
-        RefPtrWillBeRawPtr<CSSValuePair> pair = CSSValuePair::create(currentValue, offset.release(), CSSValuePair::KeepIdenticalValues);
-
         if (id == CSSValueLeft || id == CSSValueRight) {
             if (resultX)
                 return false;
-            resultX = pair.release();
+            resultX = result.release();
         } else {
             ASSERT(id == CSSValueTop || id == CSSValueBottom);
             if (resultY)
                 return false;
-            resultY = pair.release();
+            resultY = result.release();
         }
     }
 
-    if (seenCenter) {
+    if (center) {
         ASSERT(resultX || resultY);
         if (resultX && resultY)
             return false;
-        RefPtrWillBeRawPtr<CSSPrimitiveValue> offset = cssValuePool().createValue(50, CSSPrimitiveValue::UnitType::Percentage);
         if (!resultX)
-            resultX = CSSValuePair::create(cssValuePool().createIdentifierValue(CSSValueLeft), offset.release(), CSSValuePair::KeepIdenticalValues);
+            resultX = center;
         else
-            resultY = CSSValuePair::create(cssValuePool().createIdentifierValue(CSSValueTop), offset.release(), CSSValuePair::KeepIdenticalValues);
+            resultY = center;
     }
 
     ASSERT(resultX && resultY);
@@ -739,6 +721,36 @@
     return nullptr;
 }
 
+static bool consumeTransformOrigin(CSSParserTokenRange& range, CSSParserMode cssParserMode, UnitlessQuirk unitless, RefPtrWillBeRawPtr<CSSValue>& resultX, RefPtrWillBeRawPtr<CSSValue>& resultY)
+{
+    RefPtrWillBeRawPtr<CSSPrimitiveValue> value1 = consumePositionComponent(range, cssParserMode, unitless);
+    if (!value1)
+        return false;
+    RefPtrWillBeRawPtr<CSSPrimitiveValue> value2 = consumePositionComponent(range, cssParserMode, unitless);
+    if (!value2) {
+        positionFromOneValue(value1.release(), resultX, resultY);
+        return true;
+    }
+    return positionFromTwoValues(value1.release(), value2.release(), resultX, resultY);
+}
+
+static PassRefPtrWillBeRawPtr<CSSValueList> consumeTransformOrigin(CSSParserTokenRange& range, CSSParserMode cssParserMode, UnitlessQuirk unitless)
+{
+    RefPtrWillBeRawPtr<CSSValue> resultX = nullptr;
+    RefPtrWillBeRawPtr<CSSValue> resultY = nullptr;
+    if (consumeTransformOrigin(range, cssParserMode, unitless, resultX, resultY)) {
+        RefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
+        list->append(resultX.release());
+        list->append(resultY.release());
+        RefPtrWillBeRawPtr<CSSValue> resultZ = consumeLength(range, cssParserMode, ValueRangeAll);
+        if (!resultZ)
+            resultZ = cssValuePool().createValue(0, CSSPrimitiveValue::UnitType::Pixels);
+        list->append(resultZ.release());
+        return list.release();
+    }
+    return nullptr;
+}
+
 static inline bool isCSSWideKeyword(const CSSValueID& id)
 {
     return id == CSSValueInitial || id == CSSValueInherit || id == CSSValueUnset || id == CSSValueDefault;
@@ -1779,6 +1791,30 @@
     return list.release();
 }
 
+// none | strict | [ layout || style || paint ]
+static PassRefPtrWillBeRawPtr<CSSValue> consumeContain(CSSParserTokenRange& range)
+{
+    CSSValueID id = range.peek().id();
+    if (id == CSSValueNone)
+        return consumeIdent(range);
+
+    RefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
+    if (id == CSSValueStrict) {
+        list->append(consumeIdent(range));
+        return list.release();
+    }
+    RefPtrWillBeRawPtr<CSSPrimitiveValue> ident = nullptr;
+    while ((ident = consumeIdent<CSSValuePaint, CSSValueLayout, CSSValueStyle>(range))) {
+        if (list->hasValue(ident.get()))
+            return nullptr;
+        list->append(ident.release());
+    }
+
+    if (!list->length())
+        return nullptr;
+    return list.release();
+}
+
 static PassRefPtrWillBeRawPtr<CSSValue> consumeMotionPath(CSSParserTokenRange& range)
 {
     CSSValueID id = range.peek().id();
@@ -2317,6 +2353,7 @@
     case CSSPropertyTouchAction:
         return consumeTouchAction(m_range);
     case CSSPropertyObjectPosition:
+    case CSSPropertyPerspectiveOrigin:
         return consumePosition(m_range, m_context.mode(), UnitlessQuirk::Forbid);
     case CSSPropertyWebkitLineClamp:
         return consumeLineClamp(m_range);
@@ -2445,6 +2482,10 @@
         return consumeLengthOrPercent(m_range, SVGAttributeMode, ValueRangeAll, UnitlessQuirk::Forbid);
     case CSSPropertyCursor:
         return consumeCursor(m_range);
+    case CSSPropertyContain:
+        return consumeContain(m_range);
+    case CSSPropertyTransformOrigin:
+        return consumeTransformOrigin(m_range, m_context.mode(), UnitlessQuirk::Forbid);
     default:
         return nullptr;
     }
diff --git a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.h b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.h
index b1130fa..d815869 100644
--- a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.h
+++ b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.h
@@ -235,8 +235,6 @@
     PassRefPtrWillBeRawPtr<CSSValueList> parseFilter();
     PassRefPtrWillBeRawPtr<CSSFunctionValue> parseBuiltinFilterArguments(CSSParserValueList*, CSSValueID);
 
-    PassRefPtrWillBeRawPtr<CSSValueList> parseTransformOrigin();
-
     bool parseCalculation(CSSParserValue*, ValueRange);
 
     bool parseGeneratedImage(CSSParserValueList*, RefPtrWillBeRawPtr<CSSValue>&);
diff --git a/third_party/WebKit/Source/core/css/parser/LegacyCSSPropertyParser.cpp b/third_party/WebKit/Source/core/css/parser/LegacyCSSPropertyParser.cpp
index 4cb356e7..033b23d 100644
--- a/third_party/WebKit/Source/core/css/parser/LegacyCSSPropertyParser.cpp
+++ b/third_party/WebKit/Source/core/css/parser/LegacyCSSPropertyParser.cpp
@@ -572,18 +572,6 @@
     case CSSPropertyOrder:
         validPrimitive = validUnit(value, FInteger);
         break;
-    case CSSPropertyTransformOrigin: {
-        RefPtrWillBeRawPtr<CSSValueList> list = parseTransformOrigin();
-        if (!list)
-            return false;
-        // These values are added to match gecko serialization.
-        if (list->length() == 1)
-            list->append(cssValuePool().createValue(50, CSSPrimitiveValue::UnitType::Percentage));
-        if (list->length() == 2)
-            list->append(cssValuePool().createValue(0, CSSPrimitiveValue::UnitType::Pixels));
-        addProperty(propId, list.release(), important);
-        return true;
-    }
 
     case CSSPropertyWebkitPerspectiveOriginX:
     case CSSPropertyWebkitTransformOriginX:
@@ -612,16 +600,6 @@
             return false;
         }
         break;
-    case CSSPropertyPerspectiveOrigin: {
-        RefPtrWillBeRawPtr<CSSValueList> list = parseTransformOrigin();
-        if (!list || list->length() == 3)
-            return false;
-        // This values are added to match gecko serialization.
-        if (list->length() == 1)
-            list->append(cssValuePool().createValue(50, CSSPrimitiveValue::UnitType::Percentage));
-        addProperty(propId, list.release(), important);
-        return true;
-    }
 
     case CSSPropertyJustifyContent:
         ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
@@ -830,6 +808,7 @@
     case CSSPropertyWebkitLogicalWidth:
     case CSSPropertyWebkitLogicalHeight:
     case CSSPropertyObjectPosition:
+    case CSSPropertyPerspectiveOrigin:
     case CSSPropertyClip:
     case CSSPropertyTouchAction:
     case CSSPropertyWebkitLineClamp:
@@ -955,6 +934,7 @@
     case CSSPropertyScale:
     case CSSPropertyTranslate:
     case CSSPropertyCursor:
+    case CSSPropertyTransformOrigin:
         validPrimitive = false;
         break;
 
@@ -5003,73 +4983,6 @@
     return imageSet.release();
 }
 
-PassRefPtrWillBeRawPtr<CSSValueList> CSSPropertyParser::parseTransformOrigin()
-{
-    CSSParserValue* value = m_valueList->current();
-    CSSValueID id = value->id;
-    RefPtrWillBeRawPtr<CSSValue> xValue = nullptr;
-    RefPtrWillBeRawPtr<CSSValue> yValue = nullptr;
-    RefPtrWillBeRawPtr<CSSValue> zValue = nullptr;
-    if (id == CSSValueLeft || id == CSSValueRight) {
-        xValue = cssValuePool().createIdentifierValue(id);
-    } else if (id == CSSValueTop || id == CSSValueBottom) {
-        yValue = cssValuePool().createIdentifierValue(id);
-    } else if (id == CSSValueCenter) {
-        // Unresolved as to whether this is X or Y.
-    } else if (validUnit(value, FPercent | FLength)) {
-        xValue = createPrimitiveNumericValue(value);
-    } else {
-        return nullptr;
-    }
-
-    value = m_valueList->next();
-    if (value) {
-        id = value->id;
-        if (!xValue && (id == CSSValueLeft || id == CSSValueRight)) {
-            xValue = cssValuePool().createIdentifierValue(id);
-        } else if (!yValue && (id == CSSValueTop || id == CSSValueBottom)) {
-            yValue = cssValuePool().createIdentifierValue(id);
-        } else if (id == CSSValueCenter) {
-            // Resolved below.
-        } else if (!yValue && validUnit(value, FPercent | FLength)) {
-            yValue = createPrimitiveNumericValue(value);
-        } else {
-            return nullptr;
-        }
-
-        // If X or Y have not been resolved, they must be center.
-        if (!xValue)
-            xValue = cssValuePool().createIdentifierValue(CSSValueCenter);
-        if (!yValue)
-            yValue = cssValuePool().createIdentifierValue(CSSValueCenter);
-
-        value = m_valueList->next();
-        if (value) {
-            if (!validUnit(value, FLength))
-                return nullptr;
-            zValue = createPrimitiveNumericValue(value);
-
-            value = m_valueList->next();
-            if (value)
-                return nullptr;
-        }
-    } else if (!xValue) {
-        if (yValue) {
-            xValue = cssValuePool().createValue(50, CSSPrimitiveValue::UnitType::Percentage);
-        } else {
-            xValue = cssValuePool().createIdentifierValue(CSSValueCenter);
-        }
-    }
-
-    RefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
-    list->append(xValue.release());
-    if (yValue)
-        list->append(yValue.release());
-    if (zValue)
-        list->append(zValue.release());
-    return list.release();
-}
-
 bool CSSPropertyParser::parseCalculation(CSSParserValue* value, ValueRange range)
 {
     ASSERT(isCalculation(value));
diff --git a/third_party/WebKit/Source/core/css/resolver/MatchedPropertiesCache.cpp b/third_party/WebKit/Source/core/css/resolver/MatchedPropertiesCache.cpp
index 624b4818..fb94762 100644
--- a/third_party/WebKit/Source/core/css/resolver/MatchedPropertiesCache.cpp
+++ b/third_party/WebKit/Source/core/css/resolver/MatchedPropertiesCache.cpp
@@ -160,6 +160,8 @@
     // The cache assumes static knowledge about which properties are inherited.
     if (parentStyle.hasExplicitlyInheritedProperties())
         return false;
+    if (style.hasVariableReferenceFromNonInheritedProperty())
+        return false;
     return true;
 }
 
diff --git a/third_party/WebKit/Source/core/css/resolver/StyleBuilderConverter.cpp b/third_party/WebKit/Source/core/css/resolver/StyleBuilderConverter.cpp
index 42ecf49..91cb9ea 100644
--- a/third_party/WebKit/Source/core/css/resolver/StyleBuilderConverter.cpp
+++ b/third_party/WebKit/Source/core/css/resolver/StyleBuilderConverter.cpp
@@ -639,7 +639,21 @@
         return length.subtractFromOneHundredPercent();
     }
 
-    return StyleBuilderConverter::convertLength(state, value);
+    const CSSPrimitiveValue& primitiveValue = toCSSPrimitiveValue(value);
+    if (primitiveValue.isValueID()) {
+        switch (primitiveValue.getValueID()) {
+        case cssValueFor0:
+            return Length(0, Percent);
+        case cssValueFor100:
+            return Length(100, Percent);
+        case CSSValueCenter:
+            return Length(50, Percent);
+        default:
+            ASSERT_NOT_REACHED();
+        }
+    }
+
+    return StyleBuilderConverter::convertLength(state, primitiveValue);
 }
 
 LengthPoint StyleBuilderConverter::convertPosition(StyleResolverState& state, const CSSValue& value)
@@ -684,20 +698,6 @@
     return StyleBuilderConverter::convertLength(state, primitiveValue);
 }
 
-LengthPoint StyleBuilderConverter::convertPerspectiveOrigin(StyleResolverState& state, const CSSValue& value)
-{
-    const CSSValueList& list = toCSSValueList(value);
-    ASSERT(list.length() == 2);
-
-    const CSSPrimitiveValue& primitiveValueX = toCSSPrimitiveValue(*list.item(0));
-    const CSSPrimitiveValue& primitiveValueY = toCSSPrimitiveValue(*list.item(1));
-
-    return LengthPoint(
-        convertOriginLength<CSSValueLeft, CSSValueRight>(state, primitiveValueX),
-        convertOriginLength<CSSValueTop, CSSValueBottom>(state, primitiveValueY)
-    );
-}
-
 EPaintOrder StyleBuilderConverter::convertPaintOrder(StyleResolverState&, const CSSValue& cssPaintOrder)
 {
     if (cssPaintOrder.isValueList()) {
diff --git a/third_party/WebKit/Source/core/css/resolver/StyleBuilderConverter.h b/third_party/WebKit/Source/core/css/resolver/StyleBuilderConverter.h
index de660bdc..dcc5c6a7 100644
--- a/third_party/WebKit/Source/core/css/resolver/StyleBuilderConverter.h
+++ b/third_party/WebKit/Source/core/css/resolver/StyleBuilderConverter.h
@@ -80,7 +80,6 @@
     static float convertNumberOrPercentage(StyleResolverState&, const CSSValue&);
     static LengthPoint convertPosition(StyleResolverState&, const CSSValue&);
     static float convertPerspective(StyleResolverState&, const CSSValue&);
-    static LengthPoint convertPerspectiveOrigin(StyleResolverState&, const CSSValue&);
     static Length convertQuirkyLength(StyleResolverState&, const CSSValue&);
     static PassRefPtr<QuotesData> convertQuotes(StyleResolverState&, const CSSValue&);
     static LengthSize convertRadius(StyleResolverState&, const CSSValue&);
diff --git a/third_party/WebKit/Source/core/css/resolver/StyleBuilderCustom.cpp b/third_party/WebKit/Source/core/css/resolver/StyleBuilderCustom.cpp
index a7ab238..a9e843e 100644
--- a/third_party/WebKit/Source/core/css/resolver/StyleBuilderCustom.cpp
+++ b/third_party/WebKit/Source/core/css/resolver/StyleBuilderCustom.cpp
@@ -113,6 +113,8 @@
 {
     if (RuntimeEnabledFeatures::cssVariablesEnabled() && id != CSSPropertyVariable && value->isVariableReferenceValue()) {
         CSSVariableResolver::resolveAndApplyVariableReferences(state, id, *toCSSVariableReferenceValue(value));
+        if (!state.style()->hasVariableReferenceFromNonInheritedProperty() && !CSSPropertyMetadata::isInheritedProperty(id))
+            state.style()->setHasVariableReferenceFromNonInheritedProperty();
         return;
     }
 
diff --git a/third_party/WebKit/Source/core/dom/ContainerNode.cpp b/third_party/WebKit/Source/core/dom/ContainerNode.cpp
index 82cb94c..380860b 100644
--- a/third_party/WebKit/Source/core/dom/ContainerNode.cpp
+++ b/third_party/WebKit/Source/core/dom/ContainerNode.cpp
@@ -638,6 +638,7 @@
     ChildListMutationScope(*this).willRemoveChild(oldChild);
     oldChild.notifyMutationObserversNodeWillDetach();
 
+    HTMLFrameOwnerElement::UpdateSuspendScope suspendWidgetHierarchyUpdates;
     Node* prev = oldChild.previousSibling();
     Node* next = oldChild.nextSibling();
     removeBetween(prev, next, oldChild);
@@ -1082,7 +1083,7 @@
         if (computedStyle()->affectedByFocus() && computedStyle()->hasPseudoStyle(FIRST_LETTER))
             setNeedsStyleRecalc(SubtreeStyleChange, StyleChangeReasonForTracing::createWithExtraData(StyleChangeReason::PseudoClass, StyleChangeExtraData::Focus));
         else if (isElementNode() && toElement(this)->childrenOrSiblingsAffectedByFocus())
-            document().styleEngine().pseudoStateChangedForElement(CSSSelector::PseudoFocus, *toElement(this));
+            toElement(this)->pseudoStateChanged(CSSSelector::PseudoFocus);
         else if (computedStyle()->affectedByFocus())
             setNeedsStyleRecalc(LocalStyleChange, StyleChangeReasonForTracing::createWithExtraData(StyleChangeReason::PseudoClass, StyleChangeExtraData::Focus));
     }
@@ -1118,8 +1119,8 @@
         return;
 
     // If :focus sets display: none, we lose focus but still need to recalc our style.
-    if (isElementNode() && toElement(this)->childrenOrSiblingsAffectedByFocus() && styleChangeType() < SubtreeStyleChange)
-        document().styleEngine().pseudoStateChangedForElement(CSSSelector::PseudoFocus, *toElement(this));
+    if (isElementNode() && toElement(this)->childrenOrSiblingsAffectedByFocus())
+        toElement(this)->pseudoStateChanged(CSSSelector::PseudoFocus);
     else
         setNeedsStyleRecalc(LocalStyleChange, StyleChangeReasonForTracing::createWithExtraData(StyleChangeReason::PseudoClass, StyleChangeExtraData::Focus));
 }
@@ -1137,7 +1138,7 @@
             if (computedStyle()->affectedByActive() && computedStyle()->hasPseudoStyle(FIRST_LETTER))
                 setNeedsStyleRecalc(SubtreeStyleChange, StyleChangeReasonForTracing::createWithExtraData(StyleChangeReason::PseudoClass, StyleChangeExtraData::Active));
             else if (isElementNode() && toElement(this)->childrenOrSiblingsAffectedByActive())
-                document().styleEngine().pseudoStateChangedForElement(CSSSelector::PseudoActive, *toElement(this));
+                toElement(this)->pseudoStateChanged(CSSSelector::PseudoActive);
             else if (computedStyle()->affectedByActive())
                 setNeedsStyleRecalc(LocalStyleChange, StyleChangeReasonForTracing::createWithExtraData(StyleChangeReason::PseudoClass, StyleChangeExtraData::Active));
         }
@@ -1157,8 +1158,8 @@
     if (!layoutObject()) {
         if (over)
             return;
-        if (isElementNode() && toElement(this)->childrenOrSiblingsAffectedByHover() && styleChangeType() < SubtreeStyleChange)
-            document().styleEngine().pseudoStateChangedForElement(CSSSelector::PseudoHover, *toElement(this));
+        if (isElementNode() && toElement(this)->childrenOrSiblingsAffectedByHover())
+            toElement(this)->pseudoStateChanged(CSSSelector::PseudoHover);
         else
             setNeedsStyleRecalc(LocalStyleChange, StyleChangeReasonForTracing::createWithExtraData(StyleChangeReason::PseudoClass, StyleChangeExtraData::Hover));
         return;
@@ -1168,7 +1169,7 @@
         if (computedStyle()->affectedByHover() && computedStyle()->hasPseudoStyle(FIRST_LETTER))
             setNeedsStyleRecalc(SubtreeStyleChange, StyleChangeReasonForTracing::createWithExtraData(StyleChangeReason::PseudoClass, StyleChangeExtraData::Hover));
         else if (isElementNode() && toElement(this)->childrenOrSiblingsAffectedByHover())
-            document().styleEngine().pseudoStateChangedForElement(CSSSelector::PseudoHover, *toElement(this));
+            toElement(this)->pseudoStateChanged(CSSSelector::PseudoHover);
         else if (computedStyle()->affectedByHover())
             setNeedsStyleRecalc(LocalStyleChange, StyleChangeReasonForTracing::createWithExtraData(StyleChangeReason::PseudoClass, StyleChangeExtraData::Hover));
     }
diff --git a/third_party/WebKit/Source/core/dom/DOMURL.cpp b/third_party/WebKit/Source/core/dom/DOMURL.cpp
index 61c56bf..89fc742 100644
--- a/third_party/WebKit/Source/core/dom/DOMURL.cpp
+++ b/third_party/WebKit/Source/core/dom/DOMURL.cpp
@@ -64,7 +64,8 @@
 
 String DOMURL::createObjectURL(ExecutionContext* executionContext, Blob* blob, ExceptionState& exceptionState)
 {
-    if (!executionContext || !blob)
+    ASSERT(blob);
+    if (!executionContext)
         return String();
     if (blob->hasBeenClosed()) {
         exceptionState.throwDOMException(InvalidStateError, String(blob->isFile() ? "File" : "Blob") + " has been closed.");
diff --git a/third_party/WebKit/Source/core/dom/DocumentStyleSheetCollection.cpp b/third_party/WebKit/Source/core/dom/DocumentStyleSheetCollection.cpp
index 79e5cff..a3d35ad 100644
--- a/third_party/WebKit/Source/core/dom/DocumentStyleSheetCollection.cpp
+++ b/third_party/WebKit/Source/core/dom/DocumentStyleSheetCollection.cpp
@@ -82,7 +82,7 @@
 void DocumentStyleSheetCollection::collectStyleSheets(StyleEngine& engine, DocumentStyleSheetCollector& collector)
 {
     ASSERT(&document().styleEngine() == &engine);
-    collector.appendActiveStyleSheets(engine.documentAuthorStyleSheets());
+    collector.appendActiveStyleSheets(engine.injectedAuthorStyleSheets());
     collectStyleSheetsFromCandidates(engine, collector);
 }
 
diff --git a/third_party/WebKit/Source/core/dom/Element.cpp b/third_party/WebKit/Source/core/dom/Element.cpp
index b0ec8b3..d542409 100644
--- a/third_party/WebKit/Source/core/dom/Element.cpp
+++ b/third_party/WebKit/Source/core/dom/Element.cpp
@@ -2067,7 +2067,7 @@
         return;
 
     if (!style || (styleAffectedByEmpty() && (!style->emptyState() || hasChildren())))
-        document().styleEngine().pseudoStateChangedForElement(CSSSelector::PseudoEmpty, *this);
+        pseudoStateChanged(CSSSelector::PseudoEmpty);
 }
 
 void Element::childrenChanged(const ChildrenChange& change)
diff --git a/third_party/WebKit/Source/core/dom/StyleEngine.cpp b/third_party/WebKit/Source/core/dom/StyleEngine.cpp
index a5f449f..d5d9941d1c 100644
--- a/third_party/WebKit/Source/core/dom/StyleEngine.cpp
+++ b/third_party/WebKit/Source/core/dom/StyleEngine.cpp
@@ -90,8 +90,8 @@
     // Cleanup is performed eagerly when the StyleEngine is removed from the
     // document. The StyleEngine is unreachable after this, since only the
     // document has a reference to it.
-    for (unsigned i = 0; i < m_authorStyleSheets.size(); ++i)
-        m_authorStyleSheets[i]->clearOwnerNode();
+    for (unsigned i = 0; i < m_injectedAuthorStyleSheets.size(); ++i)
+        m_injectedAuthorStyleSheets[i]->clearOwnerNode();
 
     if (m_fontSelector) {
         m_fontSelector->clearDocument();
@@ -163,10 +163,10 @@
     m_maxDirectAdjacentSelectors = features.maxDirectAdjacentSelectors();
 }
 
-void StyleEngine::addAuthorSheet(PassRefPtrWillBeRawPtr<StyleSheetContents> authorSheet)
+void StyleEngine::injectAuthorSheet(PassRefPtrWillBeRawPtr<StyleSheetContents> authorSheet)
 {
-    m_authorStyleSheets.append(CSSStyleSheet::create(authorSheet, m_document));
-    document().addedStyleSheet(m_authorStyleSheets.last().get());
+    m_injectedAuthorStyleSheets.append(CSSStyleSheet::create(authorSheet, m_document));
+    document().addedStyleSheet(m_injectedAuthorStyleSheets.last().get());
     markDocumentDirty();
 }
 
@@ -711,7 +711,7 @@
 {
 #if ENABLE(OILPAN)
     visitor->trace(m_document);
-    visitor->trace(m_authorStyleSheets);
+    visitor->trace(m_injectedAuthorStyleSheets);
     visitor->trace(m_documentStyleSheetCollection);
     visitor->trace(m_styleSheetCollectionMap);
     visitor->trace(m_resolver);
diff --git a/third_party/WebKit/Source/core/dom/StyleEngine.h b/third_party/WebKit/Source/core/dom/StyleEngine.h
index 46ebb6f..931a72ca 100644
--- a/third_party/WebKit/Source/core/dom/StyleEngine.h
+++ b/third_party/WebKit/Source/core/dom/StyleEngine.h
@@ -80,7 +80,7 @@
 
     const WillBeHeapVector<RefPtrWillBeMember<StyleSheet>>& styleSheetsForStyleSheetList(TreeScope&);
 
-    const WillBeHeapVector<RefPtrWillBeMember<CSSStyleSheet>>& documentAuthorStyleSheets() const { return m_authorStyleSheets; }
+    const WillBeHeapVector<RefPtrWillBeMember<CSSStyleSheet>>& injectedAuthorStyleSheets() const { return m_injectedAuthorStyleSheets; }
 
     const WillBeHeapVector<RefPtrWillBeMember<CSSStyleSheet>> activeStyleSheetsForInspector() const;
 
@@ -90,7 +90,7 @@
     void removeStyleSheetCandidateNode(Node*, TreeScope&);
     void modifiedStyleSheetCandidateNode(Node*);
 
-    void addAuthorSheet(PassRefPtrWillBeRawPtr<StyleSheetContents> authorSheet);
+    void injectAuthorSheet(PassRefPtrWillBeRawPtr<StyleSheetContents> authorSheet);
 
     void clearMediaQueryRuleSetStyleSheets();
     void updateStyleSheetsInImport(DocumentStyleSheetCollector& parentCollector);
@@ -227,7 +227,7 @@
     // elements and when it is safe to execute scripts.
     int m_pendingStylesheets;
 
-    WillBeHeapVector<RefPtrWillBeMember<CSSStyleSheet>> m_authorStyleSheets;
+    WillBeHeapVector<RefPtrWillBeMember<CSSStyleSheet>> m_injectedAuthorStyleSheets;
 
     OwnPtrWillBeMember<DocumentStyleSheetCollection> m_documentStyleSheetCollection;
 
diff --git a/third_party/WebKit/Source/core/dom/URL.idl b/third_party/WebKit/Source/core/dom/URL.idl
index a4e75fc..f5df0bb7b 100644
--- a/third_party/WebKit/Source/core/dom/URL.idl
+++ b/third_party/WebKit/Source/core/dom/URL.idl
@@ -41,8 +41,8 @@
     // TODO(philipj): This should be in a partial interface definition:
     // File API
     // https://w3c.github.io/FileAPI/#creating-revoking
-    // TODO(philipj): Neither the return value nor the argument should be nullable.
-    [RaisesException, CallWith=ExecutionContext, LegacyInterfaceTypeChecking] static DOMString? createObjectURL(Blob? blob);
+    // TODO(philipj): The return type should not be nullable.
+    [RaisesException, CallWith=ExecutionContext] static DOMString? createObjectURL(Blob blob);
     [CallWith=ExecutionContext] static void revokeObjectURL(DOMString url);
 };
 
diff --git a/third_party/WebKit/Source/core/editing/serializers/MarkupFormatter.cpp b/third_party/WebKit/Source/core/editing/serializers/MarkupFormatter.cpp
index 7afbb55..317e8c6f 100644
--- a/third_party/WebKit/Source/core/editing/serializers/MarkupFormatter.cpp
+++ b/third_party/WebKit/Source/core/editing/serializers/MarkupFormatter.cpp
@@ -78,6 +78,9 @@
     DEFINE_STATIC_LOCAL(const CString, gtReference, ("&gt;"));
     DEFINE_STATIC_LOCAL(const CString, quotReference, ("&quot;"));
     DEFINE_STATIC_LOCAL(const CString, nbspReference, ("&nbsp;"));
+    DEFINE_STATIC_LOCAL(const CString, tabReference, ("&#9;"));
+    DEFINE_STATIC_LOCAL(const CString, lineFeedReference, ("&#10;"));
+    DEFINE_STATIC_LOCAL(const CString, carriageReturnReference, ("&#13;"));
 
     static const EntityDescription entityMaps[] = {
         { '&', ampReference, EntityAmp },
@@ -85,6 +88,9 @@
         { '>', gtReference, EntityGt },
         { '"', quotReference, EntityQuot },
         { noBreakSpaceCharacter, nbspReference, EntityNbsp },
+        { '\t', tabReference, EntityTab },
+        { '\n', lineFeedReference, EntityLineFeed },
+        { '\r', carriageReturnReference, EntityCarriageReturn },
     };
 
     if (!(offset + length))
diff --git a/third_party/WebKit/Source/core/editing/serializers/MarkupFormatter.h b/third_party/WebKit/Source/core/editing/serializers/MarkupFormatter.h
index 91732f2c..dcfd32b 100644
--- a/third_party/WebKit/Source/core/editing/serializers/MarkupFormatter.h
+++ b/third_party/WebKit/Source/core/editing/serializers/MarkupFormatter.h
@@ -47,13 +47,16 @@
     EntityGt = 0x0004,
     EntityQuot = 0x0008,
     EntityNbsp = 0x0010,
+    EntityTab = 0x0020,
+    EntityLineFeed = 0x0040,
+    EntityCarriageReturn = 0x0080,
 
     // Non-breaking space needs to be escaped in innerHTML for compatibility reason. See http://trac.webkit.org/changeset/32879
     // However, we cannot do this in a XML document because it does not have the entity reference defined (See the bug 19215).
     EntityMaskInCDATA = 0,
     EntityMaskInPCDATA = EntityAmp | EntityLt | EntityGt,
     EntityMaskInHTMLPCDATA = EntityMaskInPCDATA | EntityNbsp,
-    EntityMaskInAttributeValue = EntityAmp | EntityQuot | EntityLt | EntityGt,
+    EntityMaskInAttributeValue = EntityAmp | EntityQuot | EntityLt | EntityGt | EntityTab | EntityLineFeed | EntityCarriageReturn,
     EntityMaskInHTMLAttributeValue = EntityAmp | EntityQuot | EntityNbsp,
 };
 
diff --git a/third_party/WebKit/Source/core/editing/spellcheck/SpellChecker.cpp b/third_party/WebKit/Source/core/editing/spellcheck/SpellChecker.cpp
index e7f4955..8dbfcaae 100644
--- a/third_party/WebKit/Source/core/editing/spellcheck/SpellChecker.cpp
+++ b/third_party/WebKit/Source/core/editing/spellcheck/SpellChecker.cpp
@@ -124,11 +124,6 @@
     }
 }
 
-bool SpellChecker::isGrammarCheckingEnabled()
-{
-    return spellCheckerClient().isGrammarCheckingEnabled();
-}
-
 void SpellChecker::didBeginEditing(Element* element)
 {
     if (isContinuousSpellCheckingEnabled() && unifiedTextCheckerEnabled()) {
@@ -242,7 +237,7 @@
     if (unifiedTextCheckerEnabled()) {
         grammarSearchStart = spellingSearchStart;
         grammarSearchEnd = spellingSearchEnd;
-        foundItem = TextCheckingHelper(spellCheckerClient(), spellingSearchStart, spellingSearchEnd).findFirstMisspellingOrBadGrammar(isGrammarCheckingEnabled(), isSpelling, foundOffset, grammarDetail);
+        foundItem = TextCheckingHelper(spellCheckerClient(), spellingSearchStart, spellingSearchEnd).findFirstMisspellingOrBadGrammar(isSpelling, foundOffset, grammarDetail);
         if (isSpelling) {
             misspelledWord = foundItem;
             misspellingOffset = foundOffset;
@@ -261,8 +256,7 @@
             grammarSearchEnd = chars.startPosition();
         }
 
-        if (isGrammarCheckingEnabled())
-            badGrammarPhrase = TextCheckingHelper(spellCheckerClient(), grammarSearchStart, grammarSearchEnd).findFirstBadGrammar(grammarDetail, grammarPhraseOffset, false);
+        badGrammarPhrase = TextCheckingHelper(spellCheckerClient(), grammarSearchStart, grammarSearchEnd).findFirstBadGrammar(grammarDetail, grammarPhraseOffset, false);
     }
 
     // If we found neither bad grammar nor a misspelled word, wrap and try again (but don't bother if we started at the beginning of the
@@ -275,7 +269,7 @@
         if (unifiedTextCheckerEnabled()) {
             grammarSearchStart = spellingSearchStart;
             grammarSearchEnd = spellingSearchEnd;
-            foundItem = TextCheckingHelper(spellCheckerClient(), spellingSearchStart, spellingSearchEnd).findFirstMisspellingOrBadGrammar(isGrammarCheckingEnabled(), isSpelling, foundOffset, grammarDetail);
+            foundItem = TextCheckingHelper(spellCheckerClient(), spellingSearchStart, spellingSearchEnd).findFirstMisspellingOrBadGrammar(isSpelling, foundOffset, grammarDetail);
             if (isSpelling) {
                 misspelledWord = foundItem;
                 misspellingOffset = foundOffset;
@@ -294,8 +288,7 @@
                 grammarSearchEnd = chars.startPosition();
             }
 
-            if (isGrammarCheckingEnabled())
-                badGrammarPhrase = TextCheckingHelper(spellCheckerClient(), grammarSearchStart, grammarSearchEnd).findFirstBadGrammar(grammarDetail, grammarPhraseOffset, false);
+            badGrammarPhrase = TextCheckingHelper(spellCheckerClient(), grammarSearchStart, grammarSearchEnd).findFirstBadGrammar(grammarDetail, grammarPhraseOffset, false);
         }
     }
 
@@ -344,7 +337,7 @@
 
 void SpellChecker::markMisspellingsAndBadGrammar(const VisibleSelection &movingSelection)
 {
-    markMisspellingsAndBadGrammar(movingSelection, isContinuousSpellCheckingEnabled() && isGrammarCheckingEnabled(), movingSelection);
+    markMisspellingsAndBadGrammar(movingSelection, isContinuousSpellCheckingEnabled(), movingSelection);
 }
 
 void SpellChecker::markMisspellingsAfterLineBreak(const VisibleSelection& wordSelection)
@@ -356,14 +349,11 @@
         return;
     }
 
-    TextCheckingTypeMask textCheckingOptions = 0;
+    TextCheckingTypeMask textCheckingOptions = TextCheckingTypeGrammar;
 
     if (isContinuousSpellCheckingEnabled())
         textCheckingOptions |= TextCheckingTypeSpelling;
 
-    if (isGrammarCheckingEnabled())
-        textCheckingOptions |= TextCheckingTypeGrammar;
-
     VisibleSelection wholeParagraph(
         startOfParagraph(wordSelection.visibleStart()),
         endOfParagraph(wordSelection.visibleEnd()));
@@ -386,8 +376,7 @@
         if (!(textCheckingOptions & TextCheckingTypeSpelling))
             return;
 
-        if (isGrammarCheckingEnabled())
-            textCheckingOptions |= TextCheckingTypeGrammar;
+        textCheckingOptions |= TextCheckingTypeGrammar;
 
         VisibleSelection adjacentWords = VisibleSelection(startOfWord(wordStart, LeftWordIfOnBoundary), endOfWord(wordStart, RightWordIfOnBoundary));
         if (textCheckingOptions & TextCheckingTypeGrammar) {
@@ -405,7 +394,7 @@
     // Check spelling of one word
     bool result = markMisspellings(VisibleSelection(startOfWord(wordStart, LeftWordIfOnBoundary), endOfWord(wordStart, RightWordIfOnBoundary)));
 
-    if (!result || !isGrammarCheckingEnabled())
+    if (!result)
         return;
 
     // Check grammar of entire sentence
@@ -440,8 +429,7 @@
     if (checkSpelling)
         return checker.markAllMisspellings();
 
-    if (isGrammarCheckingEnabled())
-        checker.markAllBadGrammar();
+    checker.markAllBadGrammar();
     return false;
 }
 
@@ -635,7 +623,7 @@
 
         // markMisspellingsAndBadGrammar() is triggered by selection change, in which case we check spelling and grammar, but don't autocorrect misspellings.
         TextCheckingTypeMask textCheckingOptions = TextCheckingTypeSpelling;
-        if (markGrammar && isGrammarCheckingEnabled())
+        if (markGrammar)
             textCheckingOptions |= TextCheckingTypeGrammar;
         markAllMisspellingsAndBadGrammarInRanges(textCheckingOptions, spellingSelection.toNormalizedEphemeralRange(), grammarSelection.toNormalizedEphemeralRange());
         return;
@@ -648,9 +636,6 @@
 
 void SpellChecker::updateMarkersForWordsAffectedByEditing(bool doNotRemoveIfSelectionAtWordBoundary)
 {
-    if (textChecker().shouldEraseMarkersAfterChangeSelection(TextCheckingTypeSpelling))
-        return;
-
     TRACE_EVENT0("blink", "SpellChecker::updateMarkersForWordsAffectedByEditing");
 
     // We want to remove the markers from a word if an editing command will change the word. This can happen in one of
@@ -729,7 +714,7 @@
     HTMLTextFormControlElement* textFormControlElement = toHTMLTextFormControlElement(e);
     HTMLElement* innerEditor = textFormControlElement->innerEditorElement();
     DocumentMarker::MarkerTypes markerTypes(DocumentMarker::Spelling);
-    if (isGrammarCheckingEnabled() || unifiedTextCheckerEnabled())
+    if (unifiedTextCheckerEnabled())
         markerTypes.add(DocumentMarker::Grammar);
     for (Node& node : NodeTraversal::inclusiveDescendantsOf(*innerEditor))
         frame().document()->markers().removeMarkers(&node, markerTypes);
@@ -756,7 +741,7 @@
 
     bool closeTyping = options & FrameSelection::CloseTyping;
     bool isContinuousSpellCheckingEnabled = this->isContinuousSpellCheckingEnabled();
-    bool isContinuousGrammarCheckingEnabled = isContinuousSpellCheckingEnabled && isGrammarCheckingEnabled();
+    bool isContinuousGrammarCheckingEnabled = isContinuousSpellCheckingEnabled;
     if (isContinuousSpellCheckingEnabled) {
         VisibleSelection newAdjacentWords;
         VisibleSelection newSelectedSentence;
@@ -789,14 +774,6 @@
             && oldSelection.start().inDocument()) {
             spellCheckOldSelection(oldSelection, newAdjacentWords);
         }
-
-        // FIXME(http://crbug.com/382809):
-        // shouldEraseMarkersAfterChangeSelection is true, we cause synchronous
-        // layout.
-        if (textChecker().shouldEraseMarkersAfterChangeSelection(TextCheckingTypeSpelling))
-            removeMarkers(newAdjacentWords, DocumentMarker::Spelling);
-        if (textChecker().shouldEraseMarkersAfterChangeSelection(TextCheckingTypeGrammar))
-            removeMarkers(newSelectedSentence, DocumentMarker::Grammar);
     }
 
     // When continuous spell checking is off, existing markers disappear after the selection changes.
@@ -841,7 +818,7 @@
     VisiblePosition oldStart(oldSelection.visibleStart());
     VisibleSelection oldAdjacentWords = VisibleSelection(startOfWord(oldStart, LeftWordIfOnBoundary), endOfWord(oldStart, RightWordIfOnBoundary));
     if (!equalSelectionsInDOMTree(oldAdjacentWords, newAdjacentWords)) {
-        if (isContinuousSpellCheckingEnabled() && isGrammarCheckingEnabled()) {
+        if (isContinuousSpellCheckingEnabled()) {
             VisibleSelection selectedSentence = VisibleSelection(startOfSentence(oldStart), endOfSentence(oldStart));
             markMisspellingsAndBadGrammar(oldAdjacentWords, true, selectedSentence);
         } else {
diff --git a/third_party/WebKit/Source/core/editing/spellcheck/SpellChecker.h b/third_party/WebKit/Source/core/editing/spellcheck/SpellChecker.h
index fde20fd..f3138ab3 100644
--- a/third_party/WebKit/Source/core/editing/spellcheck/SpellChecker.h
+++ b/third_party/WebKit/Source/core/editing/spellcheck/SpellChecker.h
@@ -57,7 +57,6 @@
 
     bool isContinuousSpellCheckingEnabled() const;
     void toggleContinuousSpellChecking();
-    bool isGrammarCheckingEnabled();
     void ignoreSpelling();
     bool isSpellCheckingEnabledInFocusedNode() const;
     bool isSpellCheckingEnabledFor(Node*) const;
diff --git a/third_party/WebKit/Source/core/editing/spellcheck/TextCheckingHelper.cpp b/third_party/WebKit/Source/core/editing/spellcheck/TextCheckingHelper.cpp
index 0714e89..c2186724 100644
--- a/third_party/WebKit/Source/core/editing/spellcheck/TextCheckingHelper.cpp
+++ b/third_party/WebKit/Source/core/editing/spellcheck/TextCheckingHelper.cpp
@@ -309,7 +309,7 @@
     return firstMisspelling;
 }
 
-String TextCheckingHelper::findFirstMisspellingOrBadGrammar(bool checkGrammar, bool& outIsSpelling, int& outFirstFoundOffset, GrammarDetail& outGrammarDetail)
+String TextCheckingHelper::findFirstMisspellingOrBadGrammar(bool& outIsSpelling, int& outFirstFoundOffset, GrammarDetail& outGrammarDetail)
 {
     if (!unifiedTextCheckerEnabled())
         return "";
@@ -360,7 +360,7 @@
                 unsigned grammarDetailIndex = 0;
 
                 Vector<TextCheckingResult> results;
-                TextCheckingTypeMask checkingTypes = checkGrammar ? (TextCheckingTypeSpelling | TextCheckingTypeGrammar) : TextCheckingTypeSpelling;
+                TextCheckingTypeMask checkingTypes = TextCheckingTypeSpelling | TextCheckingTypeGrammar;
                 checkTextOfParagraph(m_client->textChecker(), paragraphString, checkingTypes, results);
 
                 for (unsigned i = 0; i < results.size(); i++) {
@@ -372,7 +372,7 @@
                         ASSERT(misspelledWord.length());
                         break;
                     }
-                    if (checkGrammar && result->decoration == TextDecorationTypeGrammar && result->location < currentEndOffset && result->location + result->length > currentStartOffset) {
+                    if (result->decoration == TextDecorationTypeGrammar && result->location < currentEndOffset && result->location + result->length > currentStartOffset) {
                         ASSERT(result->length > 0 && result->location >= 0);
                         // We can't stop after the first grammar result, since there might still be a spelling result after
                         // it begins but before the first detail in it, but we can stop if we find a second grammar result.
@@ -396,7 +396,7 @@
                     }
                 }
 
-                if (!misspelledWord.isEmpty() && (!checkGrammar || badGrammarPhrase.isEmpty() || spellingLocation <= grammarDetailLocation)) {
+                if (!misspelledWord.isEmpty() && (badGrammarPhrase.isEmpty() || spellingLocation <= grammarDetailLocation)) {
                     int spellingOffset = spellingLocation - currentStartOffset;
                     if (!firstIteration)
                         spellingOffset += TextIterator::rangeLength(m_start, paragraphStart);
@@ -405,7 +405,7 @@
                     firstFoundItem = misspelledWord;
                     break;
                 }
-                if (checkGrammar && !badGrammarPhrase.isEmpty()) {
+                if (!badGrammarPhrase.isEmpty()) {
                     int grammarPhraseOffset = grammarPhraseLocation - currentStartOffset;
                     if (!firstIteration)
                         grammarPhraseOffset += TextIterator::rangeLength(m_start, paragraphStart);
diff --git a/third_party/WebKit/Source/core/editing/spellcheck/TextCheckingHelper.h b/third_party/WebKit/Source/core/editing/spellcheck/TextCheckingHelper.h
index 176a8c4..7eae542 100644
--- a/third_party/WebKit/Source/core/editing/spellcheck/TextCheckingHelper.h
+++ b/third_party/WebKit/Source/core/editing/spellcheck/TextCheckingHelper.h
@@ -89,7 +89,7 @@
     ~TextCheckingHelper();
 
     String findFirstMisspelling(int& firstMisspellingOffset, bool markAll);
-    String findFirstMisspellingOrBadGrammar(bool checkGrammar, bool& outIsSpelling, int& outFirstFoundOffset, GrammarDetail& outGrammarDetail);
+    String findFirstMisspellingOrBadGrammar(bool& outIsSpelling, int& outFirstFoundOffset, GrammarDetail& outGrammarDetail);
     String findFirstBadGrammar(GrammarDetail& outGrammarDetail, int& outGrammarPhraseOffset, bool markAll);
     bool markAllMisspellings();
     void markAllBadGrammar();
diff --git a/third_party/WebKit/Source/core/fetch/FontResource.cpp b/third_party/WebKit/Source/core/fetch/FontResource.cpp
index 68f88e0..1c3e83b 100644
--- a/third_party/WebKit/Source/core/fetch/FontResource.cpp
+++ b/third_party/WebKit/Source/core/fetch/FontResource.cpp
@@ -117,11 +117,15 @@
     Resource::didAddClient(c);
     if (!isLoading())
         static_cast<FontResourceClient*>(c)->fontLoaded(this);
+    if (m_state == ShortLimitExceeded || m_state == LongLimitExceeded)
+        static_cast<FontResourceClient*>(c)->fontLoadShortLimitExceeded(this);
+    if (m_state == LongLimitExceeded)
+        static_cast<FontResourceClient*>(c)->fontLoadLongLimitExceeded(this);
 }
 
 void FontResource::beginLoadIfNeeded(ResourceFetcher* dl)
 {
-    if (m_state != LoadInitiated) {
+    if (stillNeedsLoad()) {
         m_state = LoadInitiated;
         Resource::load(dl, m_options);
         m_fontLoadShortLimitTimer.startOneShot(fontLoadWaitShortLimitSec, BLINK_FROM_HERE);
@@ -164,6 +168,8 @@
 {
     if (!isLoading())
         return;
+    ASSERT(m_state == LoadInitiated);
+    m_state = ShortLimitExceeded;
     ResourceClientWalker<FontResourceClient> walker(m_clients);
     while (FontResourceClient* client = walker.next())
         client->fontLoadShortLimitExceeded(this);
@@ -173,6 +179,8 @@
 {
     if (!isLoading())
         return;
+    ASSERT(m_state == ShortLimitExceeded);
+    m_state = LongLimitExceeded;
     ResourceClientWalker<FontResourceClient> walker(m_clients);
     while (FontResourceClient* client = walker.next())
         client->fontLoadLongLimitExceeded(this);
diff --git a/third_party/WebKit/Source/core/fetch/FontResource.h b/third_party/WebKit/Source/core/fetch/FontResource.h
index 6e6db47b..9a582c8 100644
--- a/third_party/WebKit/Source/core/fetch/FontResource.h
+++ b/third_party/WebKit/Source/core/fetch/FontResource.h
@@ -52,7 +52,7 @@
 
     void allClientsRemoved() override;
     void beginLoadIfNeeded(ResourceFetcher* dl);
-    bool stillNeedsLoad() const override { return m_state != LoadInitiated; }
+    bool stillNeedsLoad() const override { return m_state < LoadInitiated; }
 
     bool loadScheduled() const { return m_state != Unloaded; }
     void didScheduleLoad();
@@ -85,7 +85,7 @@
     void fontLoadShortLimitCallback(Timer<FontResource>*);
     void fontLoadLongLimitCallback(Timer<FontResource>*);
 
-    enum State { Unloaded, LoadScheduled, LoadInitiated };
+    enum State { Unloaded, LoadScheduled, LoadInitiated, ShortLimitExceeded, LongLimitExceeded };
 
     OwnPtr<FontCustomPlatformData> m_fontData;
     String m_otsParsingMessage;
diff --git a/third_party/WebKit/Source/core/fetch/LinkFetchResource.cpp b/third_party/WebKit/Source/core/fetch/LinkFetchResource.cpp
index b47985a..7af3b54 100644
--- a/third_party/WebKit/Source/core/fetch/LinkFetchResource.cpp
+++ b/third_party/WebKit/Source/core/fetch/LinkFetchResource.cpp
@@ -13,8 +13,7 @@
 
 ResourcePtr<Resource> LinkFetchResource::fetch(Resource::Type type, FetchRequest& request, ResourceFetcher* fetcher)
 {
-    // TODO(yoav): Enforce a LinkPreload context here, once we know we're adding one - https://github.com/whatwg/fetch/issues/36
-    ASSERT(type == LinkPrefetch || type == LinkSubresource || type == LinkPreload);
+    ASSERT(type == LinkPrefetch || type == LinkSubresource);
     ASSERT(request.resourceRequest().frameType() == WebURLRequest::FrameTypeNone);
     fetcher->determineRequestContext(request.mutableResourceRequest(), type);
     return fetcher->requestResource(request, LinkResourceFactory(type));
diff --git a/third_party/WebKit/Source/core/fetch/MemoryCache.cpp b/third_party/WebKit/Source/core/fetch/MemoryCache.cpp
index c609a0e..3e50498 100644
--- a/third_party/WebKit/Source/core/fetch/MemoryCache.cpp
+++ b/third_party/WebKit/Source/core/fetch/MemoryCache.cpp
@@ -176,17 +176,6 @@
     WTF_LOG(ResourceLoading, "MemoryCache::add Added '%s', resource %p\n", resource->url().string().latin1().data(), resource);
 }
 
-void MemoryCache::replace(Resource* newResource, Resource* oldResource)
-{
-    ASSERT(newResource->cacheIdentifier() == oldResource->cacheIdentifier());
-    ResourceMap* resources = ensureResourceMap(oldResource->cacheIdentifier());
-    if (MemoryCacheEntry* oldEntry = resources->get(oldResource->url()))
-        evict(oldEntry);
-    add(newResource);
-    if (newResource->decodedSize() && newResource->hasClients())
-        insertInLiveDecodedResourcesList(resources->get(newResource->url()));
-}
-
 void MemoryCache::remove(Resource* resource)
 {
     // The resource may have already been removed by someone other than our caller,
@@ -342,7 +331,12 @@
         while (current) {
             // Protect 'previous' so it can't get deleted during destroyDecodedData().
             MemoryCacheEntry* previous = current->m_previousInAllResourcesList;
-            ASSERT(!previous || contains(previous->m_resource.get()));
+            if (previous) {
+                // These release assertions are for investigating crashes and
+                // should be removed shortly.
+                RELEASE_ASSERT(previous->m_resource);
+                RELEASE_ASSERT(contains(previous->m_resource.get()));
+            }
             if (!current->m_resource->hasClients() && !current->m_resource->isPreloaded() && current->m_resource->isLoaded()) {
                 // Destroy our decoded data. This will remove us from
                 // m_liveDecodedResources, and possibly move us to a different
@@ -363,7 +357,12 @@
         current = m_allResources[i].m_tail;
         while (current) {
             MemoryCacheEntry* previous = current->m_previousInAllResourcesList;
-            ASSERT(!previous || contains(previous->m_resource.get()));
+            if (previous) {
+                // These release assertions are for investigating crashes and
+                // should be removed shortly.
+                RELEASE_ASSERT(previous->m_resource);
+                RELEASE_ASSERT(contains(previous->m_resource.get()));
+            }
             if (!current->m_resource->hasClients() && !current->m_resource->isPreloaded()
                 && !current->m_resource->isCacheValidator() && current->m_resource->canDelete()
                 && current->m_resource->type() != Resource::MainResource) {
diff --git a/third_party/WebKit/Source/core/fetch/MemoryCache.h b/third_party/WebKit/Source/core/fetch/MemoryCache.h
index b0085ca..ad1cb6a65 100644
--- a/third_party/WebKit/Source/core/fetch/MemoryCache.h
+++ b/third_party/WebKit/Source/core/fetch/MemoryCache.h
@@ -179,7 +179,6 @@
     WillBeHeapVector<RawPtrWillBeMember<Resource>> resourcesForURL(const KURL&);
 
     void add(Resource*);
-    void replace(Resource* newResource, Resource* oldResource);
     void remove(Resource*);
     bool contains(const Resource*) const;
 
diff --git a/third_party/WebKit/Source/core/fetch/MemoryCacheTest.cpp b/third_party/WebKit/Source/core/fetch/MemoryCacheTest.cpp
index 2cd0334..e4fbc14e 100644
--- a/third_party/WebKit/Source/core/fetch/MemoryCacheTest.cpp
+++ b/third_party/WebKit/Source/core/fetch/MemoryCacheTest.cpp
@@ -487,22 +487,6 @@
     }
 }
 
-TEST_F(MemoryCacheTest, MultipleReplace)
-{
-    ResourcePtr<FakeResource> resource1 = new FakeResource(ResourceRequest("http://test/resource"), Resource::Raw);
-    memoryCache()->add(resource1.get());
-
-    ResourcePtr<FakeResource> resource2 = new FakeResource(ResourceRequest("http://test/resource"), Resource::Raw);
-    memoryCache()->replace(resource2.get(), resource1.get());
-    EXPECT_TRUE(memoryCache()->contains(resource2.get()));
-    EXPECT_FALSE(memoryCache()->contains(resource1.get()));
-
-    ResourcePtr<FakeResource> resource3 = new FakeResource(ResourceRequest("http://test/resource"), Resource::Raw);
-    memoryCache()->replace(resource3.get(), resource2.get());
-    EXPECT_TRUE(memoryCache()->contains(resource3.get()));
-    EXPECT_FALSE(memoryCache()->contains(resource2.get()));
-}
-
 TEST_F(MemoryCacheTest, RemoveDuringRevalidation)
 {
     ResourcePtr<FakeResource> resource1 = new FakeResource(ResourceRequest("http://test/resource"), Resource::Raw);
@@ -519,11 +503,6 @@
     memoryCache()->add(resource3.get());
     EXPECT_TRUE(memoryCache()->contains(resource3.get()));
     EXPECT_FALSE(memoryCache()->contains(resource2.get()));
-
-    memoryCache()->replace(resource1.get(), resource2.get());
-    EXPECT_TRUE(memoryCache()->contains(resource1.get()));
-    EXPECT_FALSE(memoryCache()->contains(resource2.get()));
-    EXPECT_FALSE(memoryCache()->contains(resource3.get()));
 }
 
 TEST_F(MemoryCacheTest, ResourceMapIsolation)
@@ -551,13 +530,6 @@
     EXPECT_FALSE(memoryCache()->contains(resource2.get()));
     EXPECT_TRUE(memoryCache()->contains(resource3.get()));
 
-    ResourcePtr<FakeResource> resource4 = new FakeResource(ResourceRequest("http://test/resource"), Resource::Raw);
-    resource4->setCacheIdentifier("foo");
-    memoryCache()->replace(resource4.get(), resource3.get());
-    EXPECT_TRUE(memoryCache()->contains(resource1.get()));
-    EXPECT_FALSE(memoryCache()->contains(resource3.get()));
-    EXPECT_TRUE(memoryCache()->contains(resource4.get()));
-
     WillBeHeapVector<RawPtrWillBeMember<Resource>> resources = memoryCache()->resourcesForURL(url);
     EXPECT_EQ(2u, resources.size());
 
diff --git a/third_party/WebKit/Source/core/fetch/Resource.cpp b/third_party/WebKit/Source/core/fetch/Resource.cpp
index ffca995..36811503 100644
--- a/third_party/WebKit/Source/core/fetch/Resource.cpp
+++ b/third_party/WebKit/Source/core/fetch/Resource.cpp
@@ -1098,8 +1098,6 @@
         return "Link prefetch resource";
     case Resource::LinkSubresource:
         return "Link subresource";
-    case Resource::LinkPreload:
-        return "Link preload";
     case Resource::TextTrack:
         return "Text track";
     case Resource::ImportResource:
@@ -1149,8 +1147,6 @@
         return "LinkPrefetch";
     case Resource::LinkSubresource:
         return "LinkSubresource";
-    case Resource::LinkPreload:
-        return "LinkPreload";
     case Resource::TextTrack:
         return "TextTrack";
     case Resource::ImportResource:
diff --git a/third_party/WebKit/Source/core/fetch/Resource.h b/third_party/WebKit/Source/core/fetch/Resource.h
index 12fcfa6..39bca1c 100644
--- a/third_party/WebKit/Source/core/fetch/Resource.h
+++ b/third_party/WebKit/Source/core/fetch/Resource.h
@@ -77,7 +77,6 @@
         XSLStyleSheet,
         LinkPrefetch,
         LinkSubresource,
-        LinkPreload,
         TextTrack,
         ImportResource,
         Media // Audio or video file requested by a HTML5 media element
diff --git a/third_party/WebKit/Source/core/fetch/ResourceFetcher.cpp b/third_party/WebKit/Source/core/fetch/ResourceFetcher.cpp
index 93c0806b..96d11361 100644
--- a/third_party/WebKit/Source/core/fetch/ResourceFetcher.cpp
+++ b/third_party/WebKit/Source/core/fetch/ResourceFetcher.cpp
@@ -95,7 +95,6 @@
         return ResourceLoadPriorityLow;
     case Resource::Image:
     case Resource::LinkPrefetch:
-    case Resource::LinkPreload:
         return ResourceLoadPriorityVeryLow;
     }
 
@@ -154,10 +153,6 @@
         return WebURLRequest::RequestContextPrefetch;
     case Resource::LinkSubresource:
         return WebURLRequest::RequestContextSubresource;
-    case Resource::LinkPreload:
-        // TODO(yoav): We should give preload its own context:
-        // https://github.com/whatwg/fetch/commit/26e5cca8ab5bb4b68a8f238f41dd7364d8c276b3
-        return WebURLRequest::RequestContextSubresource;
     case Resource::TextTrack:
         return WebURLRequest::RequestContextTrack;
     case Resource::SVGDocument:
@@ -470,10 +465,15 @@
         context().addResourceTiming(*timingInfo);
 }
 
+void ResourceFetcher::determineRequestContext(ResourceRequest& request, Resource::Type type, bool isMainFrame)
+{
+    WebURLRequest::RequestContext requestContext = requestContextFromType(isMainFrame, type);
+    request.setRequestContext(requestContext);
+}
+
 void ResourceFetcher::determineRequestContext(ResourceRequest& request, Resource::Type type)
 {
-    WebURLRequest::RequestContext requestContext = requestContextFromType(context().isMainFrame(), type);
-    request.setRequestContext(requestContext);
+    determineRequestContext(request, type, context().isMainFrame());
 }
 
 void ResourceFetcher::initializeResourceRequest(ResourceRequest& request, Resource::Type type)
diff --git a/third_party/WebKit/Source/core/fetch/ResourceFetcher.h b/third_party/WebKit/Source/core/fetch/ResourceFetcher.h
index f74b5eb..992bc49 100644
--- a/third_party/WebKit/Source/core/fetch/ResourceFetcher.h
+++ b/third_party/WebKit/Source/core/fetch/ResourceFetcher.h
@@ -144,6 +144,7 @@
 
     void scheduleDocumentResourcesGC();
     bool clientDefersImage(const KURL&) const;
+    static void determineRequestContext(ResourceRequest&, Resource::Type, bool isMainFrame);
     void determineRequestContext(ResourceRequest&, Resource::Type);
 
     WebTaskRunner* loadingTaskRunner();
diff --git a/third_party/WebKit/Source/core/frame/Frame.cpp b/third_party/WebKit/Source/core/frame/Frame.cpp
index b5cbebb..4ac536f 100644
--- a/third_party/WebKit/Source/core/frame/Frame.cpp
+++ b/third_party/WebKit/Source/core/frame/Frame.cpp
@@ -288,13 +288,6 @@
     return nullptr;
 }
 
-void Frame::scheduleVisualUpdateUnlessThrottled()
-{
-    if (isLocalFrame() && toLocalFrame(this)->shouldThrottleRendering())
-        return;
-    page()->animator().scheduleVisualUpdate();
-}
-
 Frame::Frame(FrameClient* client, FrameHost* host, FrameOwner* owner)
     : m_treeNode(this)
     , m_host(host)
diff --git a/third_party/WebKit/Source/core/frame/Frame.h b/third_party/WebKit/Source/core/frame/Frame.h
index 24909d3d..c15b094 100644
--- a/third_party/WebKit/Source/core/frame/Frame.h
+++ b/third_party/WebKit/Source/core/frame/Frame.h
@@ -60,6 +60,9 @@
 // Status of user gesture.
 enum class UserGestureStatus { Active, None };
 
+// Frame is the base class of LocalFrame and RemoteFrame and should only contain
+// functionality shared between both. In particular, any method related to
+// input, layout, or painting probably belongs on LocalFrame.
 class CORE_EXPORT Frame : public RefCountedWillBeGarbageCollectedFinalized<Frame> {
 public:
     virtual ~Frame();
@@ -130,8 +133,6 @@
 
     virtual WindowProxyManager* windowProxyManager() const = 0;
 
-    void scheduleVisualUpdateUnlessThrottled();
-
 protected:
     Frame(FrameClient*, FrameHost*, FrameOwner*);
 
diff --git a/third_party/WebKit/Source/core/frame/LocalFrame.cpp b/third_party/WebKit/Source/core/frame/LocalFrame.cpp
index 7f8da12..549efa6 100644
--- a/third_party/WebKit/Source/core/frame/LocalFrame.cpp
+++ b/third_party/WebKit/Source/core/frame/LocalFrame.cpp
@@ -904,6 +904,13 @@
     return m_frameScheduler.get();
 }
 
+void LocalFrame::scheduleVisualUpdateUnlessThrottled()
+{
+    if (shouldThrottleRendering())
+        return;
+    page()->animator().scheduleVisualUpdate();
+}
+
 void LocalFrame::updateSecurityOrigin(SecurityOrigin* origin)
 {
     script().updateSecurityOrigin(origin);
diff --git a/third_party/WebKit/Source/core/frame/LocalFrame.h b/third_party/WebKit/Source/core/frame/LocalFrame.h
index 32000d8..1ec0848e 100644
--- a/third_party/WebKit/Source/core/frame/LocalFrame.h
+++ b/third_party/WebKit/Source/core/frame/LocalFrame.h
@@ -186,6 +186,7 @@
 
     // Returns the frame scheduler, creating one if needed.
     WebFrameScheduler* frameScheduler();
+    void scheduleVisualUpdateUnlessThrottled();
 
     void updateSecurityOrigin(SecurityOrigin*);
 
diff --git a/third_party/WebKit/Source/core/frame/RemoteDOMWindow.cpp b/third_party/WebKit/Source/core/frame/RemoteDOMWindow.cpp
index 56bacf32..e6935ed6 100644
--- a/third_party/WebKit/Source/core/frame/RemoteDOMWindow.cpp
+++ b/third_party/WebKit/Source/core/frame/RemoteDOMWindow.cpp
@@ -344,4 +344,9 @@
 {
 }
 
+void RemoteDOMWindow::frameDetached()
+{
+    m_frame = nullptr;
+}
+
 } // namespace blink
diff --git a/third_party/WebKit/Source/core/frame/RemoteDOMWindow.h b/third_party/WebKit/Source/core/frame/RemoteDOMWindow.h
index 35b796b6..27cc423 100644
--- a/third_party/WebKit/Source/core/frame/RemoteDOMWindow.h
+++ b/third_party/WebKit/Source/core/frame/RemoteDOMWindow.h
@@ -80,6 +80,8 @@
     int requestIdleCallback(IdleRequestCallback*, const IdleRequestOptions&) override;
     void cancelIdleCallback(int id) override;
 
+    void frameDetached();
+
 private:
     explicit RemoteDOMWindow(RemoteFrame&);
 
diff --git a/third_party/WebKit/Source/core/frame/RemoteFrame.cpp b/third_party/WebKit/Source/core/frame/RemoteFrame.cpp
index 88ba745..5d7965a 100644
--- a/third_party/WebKit/Source/core/frame/RemoteFrame.cpp
+++ b/third_party/WebKit/Source/core/frame/RemoteFrame.cpp
@@ -8,6 +8,7 @@
 #include "bindings/core/v8/WindowProxy.h"
 #include "bindings/core/v8/WindowProxyManager.h"
 #include "core/dom/RemoteSecurityContext.h"
+#include "core/frame/LocalFrame.h"
 #include "core/frame/RemoteDOMWindow.h"
 #include "core/frame/RemoteFrameClient.h"
 #include "core/frame/RemoteFrameView.h"
@@ -145,6 +146,14 @@
     // Oilpan: as RemoteFrameView performs no finalization actions,
     // no explicit dispose() of it needed here. (cf. FrameView::dispose().)
     m_view = view;
+
+    // ... the RemoteDOMWindow will need to be informed of detachment,
+    // as otherwise it will keep a strong reference back to this RemoteFrame.
+    // That combined with wrappers (owned and kept alive by RemoteFrame) keeping
+    // persistent strong references to RemoteDOMWindow will prevent the GCing
+    // of all these objects. Break the cycle by notifying of detachment.
+    if (!m_view)
+        m_domWindow->frameDetached();
 }
 
 void RemoteFrame::createView()
@@ -179,4 +188,9 @@
     toHTMLFrameOwnerElement(owner())->setNeedsCompositingUpdate();
 }
 
+void RemoteFrame::advanceFocus(WebFocusType type, LocalFrame* source)
+{
+    remoteFrameClient()->advanceFocus(type, source);
+}
+
 } // namespace blink
diff --git a/third_party/WebKit/Source/core/frame/RemoteFrame.h b/third_party/WebKit/Source/core/frame/RemoteFrame.h
index c12ec4b..21e0c4e 100644
--- a/third_party/WebKit/Source/core/frame/RemoteFrame.h
+++ b/third_party/WebKit/Source/core/frame/RemoteFrame.h
@@ -8,11 +8,13 @@
 #include "core/CoreExport.h"
 #include "core/dom/RemoteSecurityContext.h"
 #include "core/frame/Frame.h"
+#include "public/platform/WebFocusType.h"
 
 namespace blink {
 
 class Event;
 class IntRect;
+class LocalFrame;
 class RemoteDOMWindow;
 class RemoteFrameClient;
 class RemoteFrameView;
@@ -50,6 +52,8 @@
     void setRemotePlatformLayer(WebLayer*);
     WebLayer* remotePlatformLayer() const { return m_remotePlatformLayer; }
 
+    void advanceFocus(WebFocusType, LocalFrame* source);
+
     void setView(PassRefPtrWillBeRawPtr<RemoteFrameView>);
     void createView();
 
diff --git a/third_party/WebKit/Source/core/frame/RemoteFrameClient.h b/third_party/WebKit/Source/core/frame/RemoteFrameClient.h
index 50d88f8..7beb80a 100644
--- a/third_party/WebKit/Source/core/frame/RemoteFrameClient.h
+++ b/third_party/WebKit/Source/core/frame/RemoteFrameClient.h
@@ -8,6 +8,7 @@
 #include "core/frame/FrameClient.h"
 #include "core/frame/FrameTypes.h"
 #include "core/loader/FrameLoaderTypes.h"
+#include "public/platform/WebFocusType.h"
 
 namespace blink {
 
@@ -28,6 +29,8 @@
     virtual void forwardInputEvent(Event*) = 0;
 
     virtual void frameRectsChanged(const IntRect& frameRect) = 0;
+
+    virtual void advanceFocus(WebFocusType, LocalFrame* source) = 0;
 };
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/core/frame/Settings.in b/third_party/WebKit/Source/core/frame/Settings.in
index c54a085..13b686e 100644
--- a/third_party/WebKit/Source/core/frame/Settings.in
+++ b/third_party/WebKit/Source/core/frame/Settings.in
@@ -96,8 +96,6 @@
 # WebAudio support.
 webAudioEnabled initial=false
 
-asynchronousSpellCheckingEnabled initial=false
-
 hyperlinkAuditingEnabled initial=false
 allowDisplayOfInsecureContent initial=true
 allowRunningOfInsecureContent initial=true
diff --git a/third_party/WebKit/Source/core/frame/UseCounter.cpp b/third_party/WebKit/Source/core/frame/UseCounter.cpp
index 80baf8d3..63f6db30 100644
--- a/third_party/WebKit/Source/core/frame/UseCounter.cpp
+++ b/third_party/WebKit/Source/core/frame/UseCounter.cpp
@@ -549,6 +549,7 @@
     case CSSPropertyFontFeatureSettings: return 514;
     case CSSPropertyVariable: return 515;
     case CSSPropertyFontDisplay: return 516;
+    case CSSPropertyContain: return 517;
 
     // 1. Add new features above this line (don't change the assigned numbers of the existing
     // items).
@@ -565,7 +566,7 @@
     return 0;
 }
 
-static int maximumCSSSampleId() { return 516; }
+static int maximumCSSSampleId() { return 517; }
 
 void UseCounter::muteForInspector()
 {
diff --git a/third_party/WebKit/Source/core/frame/UseCounter.h b/third_party/WebKit/Source/core/frame/UseCounter.h
index c68a5459..445fa206 100644
--- a/third_party/WebKit/Source/core/frame/UseCounter.h
+++ b/third_party/WebKit/Source/core/frame/UseCounter.h
@@ -896,6 +896,24 @@
         PresentationConnectionClose = 1038,
         SVG1DOMShape = 1039,
         SVG1DOMText = 1040,
+        RTCPeerConnectionConstructorConstraints = 1041,
+        RTCPeerConnectionConstructorCompliant = 1042,
+        RTCPeerConnectionCreateOfferLegacyNoFailureCallback = 1043,
+        RTCPeerConnectionCreateOfferLegacyFailureCallback = 1044,
+        RTCPeerConnectionCreateOfferLegacyConstraints = 1045,
+        RTCPeerConnectionCreateOfferLegacyOfferOptions = 1046,
+        RTCPeerConnectionCreateOfferLegacyCompliant = 1047,
+        RTCPeerConnectionCreateAnswerLegacyNoFailureCallback = 1048,
+        RTCPeerConnectionCreateAnswerLegacyFailureCallback = 1049,
+        RTCPeerConnectionCreateAnswerLegacyConstraints = 1050,
+        RTCPeerConnectionCreateAnswerLegacyCompliant = 1051,
+        RTCPeerConnectionSetLocalDescriptionLegacyNoSuccessCallback = 1052,
+        RTCPeerConnectionSetLocalDescriptionLegacyNoFailureCallback = 1053,
+        RTCPeerConnectionSetLocalDescriptionLegacyCompliant = 1054,
+        RTCPeerConnectionSetRemoteDescriptionLegacyNoSuccessCallback = 1055,
+        RTCPeerConnectionSetRemoteDescriptionLegacyNoFailureCallback = 1056,
+        RTCPeerConnectionSetRemoteDescriptionLegacyCompliant = 1057,
+        RTCPeerConnectionGetStatsLegacyNonCompliant = 1058,
 
         // Add new features immediately above this line. Don't change assigned
         // numbers of any item, and don't reuse removed slots.
diff --git a/third_party/WebKit/Source/core/frame/csp/CSPDirectiveList.cpp b/third_party/WebKit/Source/core/frame/csp/CSPDirectiveList.cpp
index d6f38fc..898d4fa 100644
--- a/third_party/WebKit/Source/core/frame/csp/CSPDirectiveList.cpp
+++ b/third_party/WebKit/Source/core/frame/csp/CSPDirectiveList.cpp
@@ -73,21 +73,21 @@
 {
     String message = m_reportOnly ? "[Report Only] " + consoleMessage : consoleMessage;
     m_policy->logToConsole(ConsoleMessage::create(SecurityMessageSource, ErrorMessageLevel, message));
-    m_policy->reportViolation(directiveText, effectiveDirective, message, blockedURL, m_reportEndpoints, m_header);
+    m_policy->reportViolation(directiveText, effectiveDirective, message, blockedURL, m_reportEndpoints, m_header, ContentSecurityPolicy::URLViolation);
 }
 
 void CSPDirectiveList::reportViolationWithFrame(const String& directiveText, const String& effectiveDirective, const String& consoleMessage, const KURL& blockedURL, LocalFrame* frame) const
 {
     String message = m_reportOnly ? "[Report Only] " + consoleMessage : consoleMessage;
     m_policy->logToConsole(ConsoleMessage::create(SecurityMessageSource, ErrorMessageLevel, message), frame);
-    m_policy->reportViolation(directiveText, effectiveDirective, message, blockedURL, m_reportEndpoints, m_header, frame);
+    m_policy->reportViolation(directiveText, effectiveDirective, message, blockedURL, m_reportEndpoints, m_header, ContentSecurityPolicy::URLViolation, frame);
 }
 
 void CSPDirectiveList::reportViolationWithLocation(const String& directiveText, const String& effectiveDirective, const String& consoleMessage, const KURL& blockedURL, const String& contextURL, const WTF::OrdinalNumber& contextLine) const
 {
     String message = m_reportOnly ? "[Report Only] " + consoleMessage : consoleMessage;
     m_policy->logToConsole(ConsoleMessage::create(SecurityMessageSource, ErrorMessageLevel, message, contextURL, contextLine.oneBasedInt()));
-    m_policy->reportViolation(directiveText, effectiveDirective, message, blockedURL, m_reportEndpoints, m_header);
+    m_policy->reportViolation(directiveText, effectiveDirective, message, blockedURL, m_reportEndpoints, m_header, ContentSecurityPolicy::InlineViolation);
 }
 
 void CSPDirectiveList::reportViolationWithState(const String& directiveText, const String& effectiveDirective, const String& message, const KURL& blockedURL, ScriptState* scriptState, const ContentSecurityPolicy::ExceptionStatus exceptionStatus) const
@@ -102,7 +102,7 @@
         consoleMessage->setScriptState(scriptState);
         m_policy->logToConsole(consoleMessage.release());
     }
-    m_policy->reportViolation(directiveText, effectiveDirective, message, blockedURL, m_reportEndpoints, m_header);
+    m_policy->reportViolation(directiveText, effectiveDirective, message, blockedURL, m_reportEndpoints, m_header, ContentSecurityPolicy::EvalViolation);
 }
 
 bool CSPDirectiveList::checkEval(SourceListDirective* directive) const
diff --git a/third_party/WebKit/Source/core/frame/csp/ContentSecurityPolicy.cpp b/third_party/WebKit/Source/core/frame/csp/ContentSecurityPolicy.cpp
index cb2a42ea2..630aba8 100644
--- a/third_party/WebKit/Source/core/frame/csp/ContentSecurityPolicy.cpp
+++ b/third_party/WebKit/Source/core/frame/csp/ContentSecurityPolicy.cpp
@@ -724,8 +724,9 @@
     }
 }
 
-void ContentSecurityPolicy::reportViolation(const String& directiveText, const String& effectiveDirective, const String& consoleMessage, const KURL& blockedURL, const Vector<String>& reportEndpoints, const String& header, LocalFrame* contextFrame)
+void ContentSecurityPolicy::reportViolation(const String& directiveText, const String& effectiveDirective, const String& consoleMessage, const KURL& blockedURL, const Vector<String>& reportEndpoints, const String& header, ViolationType violationType, LocalFrame* contextFrame)
 {
+    ASSERT(violationType == URLViolation || blockedURL.isEmpty());
     ASSERT((m_executionContext && !contextFrame) || (equalIgnoringCase(effectiveDirective, ContentSecurityPolicy::FrameAncestors) && contextFrame));
 
     // FIXME: Support sending reports from worker.
@@ -768,7 +769,17 @@
     cspReport->setString("violated-directive", violationData.violatedDirective());
     cspReport->setString("effective-directive", violationData.effectiveDirective());
     cspReport->setString("original-policy", violationData.originalPolicy());
-    cspReport->setString("blocked-uri", violationData.blockedURI());
+    switch (violationType) {
+    case InlineViolation:
+        cspReport->setString("blocked-uri", "inline");
+        break;
+    case EvalViolation:
+        cspReport->setString("blocked-uri", "eval");
+        break;
+    case URLViolation:
+        cspReport->setString("blocked-uri", violationData.blockedURI());
+        break;
+    }
     if (!violationData.sourceFile().isEmpty() && violationData.lineNumber()) {
         cspReport->setString("source-file", violationData.sourceFile());
         cspReport->setNumber("line-number", violationData.lineNumber());
diff --git a/third_party/WebKit/Source/core/frame/csp/ContentSecurityPolicy.h b/third_party/WebKit/Source/core/frame/csp/ContentSecurityPolicy.h
index df15db7..7a37106 100644
--- a/third_party/WebKit/Source/core/frame/csp/ContentSecurityPolicy.h
+++ b/third_party/WebKit/Source/core/frame/csp/ContentSecurityPolicy.h
@@ -123,6 +123,16 @@
         WillNotThrowException
     };
 
+    // This covers the possible values of a violation's 'resource', as defined in
+    // https://w3c.github.io/webappsec-csp/#violation-resource. By the time we
+    // generate a report, we're guaranteed that the value isn't 'null', so we don't
+    // need that state in this enum.
+    enum ViolationType {
+        InlineViolation,
+        EvalViolation,
+        URLViolation
+    };
+
     static PassRefPtrWillBeRawPtr<ContentSecurityPolicy> create()
     {
         return adoptRefWillBeNoop(new ContentSecurityPolicy());
@@ -226,7 +236,7 @@
     // If a frame is passed in, the report will be sent using it as a context. If no frame is
     // passed in, the report will be sent via this object's |m_executionContext| (or dropped
     // on the floor if no such context is available).
-    void reportViolation(const String& directiveText, const String& effectiveDirective, const String& consoleMessage, const KURL& blockedURL, const Vector<String>& reportEndpoints, const String& header, LocalFrame* = nullptr);
+    void reportViolation(const String& directiveText, const String& effectiveDirective, const String& consoleMessage, const KURL& blockedURL, const Vector<String>& reportEndpoints, const String& header, ViolationType, LocalFrame* = nullptr);
 
     void reportBlockedScriptExecutionToInspector(const String& directiveText) const;
 
diff --git a/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp b/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp
index badbe171..b723253 100644
--- a/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp
@@ -384,13 +384,6 @@
     removeElementFromDocumentMap(this, &document());
 
     // Destroying the player may cause a resource load to be canceled,
-    // which could result in userCancelledLoad() being called back.
-    // Setting m_isFinalizing ensures that such a call will not cause
-    // us to dispatch an abort event, which would result in a crash.
-    // See http://crbug.com/233654 for more details.
-    m_isFinalizing = true;
-
-    // Destroying the player may cause a resource load to be canceled,
     // which could result in Document::dispatchWindowLoadEvent() being
     // called via ResourceFetch::didLoadResource() then
     // FrameLoader::checkCompleted(). To prevent load event dispatching during
@@ -474,10 +467,12 @@
 
     // FIXME: This is a temporary fix to prevent this object from causing the
     // MediaPlayer to dereference LocalFrame and FrameLoader pointers from the
-    // previous document. A proper fix would provide a mechanism to allow this
-    // object to refresh the MediaPlayer's LocalFrame and FrameLoader references on
+    // previous document. This restarts the load, as if the src attribute had been set.
+    // A proper fix would provide a mechanism to allow this object to refresh
+    // the MediaPlayer's LocalFrame and FrameLoader references on
     // document changes so that playback can be resumed properly.
-    userCancelledLoad();
+    clearMediaPlayer(LoadMediaResource);
+    scheduleDelayedAction(LoadMediaResource);
 
     // Decrement the load event delay count on oldDocument now that m_webMediaPlayer has been destroyed
     // and there is no risk of dispatching a load event from within the destructor.
@@ -2978,50 +2973,6 @@
     m_playbackProgressTimer.stop();
 }
 
-void HTMLMediaElement::userCancelledLoad()
-{
-    WTF_LOG(Media, "HTMLMediaElement::userCancelledLoad(%p)", this);
-
-    // If the media data fetching process is aborted by the user:
-
-    // 1 - The user agent should cancel the fetching process.
-    clearMediaPlayer(-1);
-    // Reset m_readyState and m_readyStateMaximum since m_webMediaPlayer is gone.
-    ReadyState readyState = m_readyState;
-    m_readyState = HAVE_NOTHING;
-    m_readyStateMaximum = HAVE_NOTHING;
-
-    // TODO(srirama.m): Investigate if this condition can be dropped entirely without any issues.
-    if (m_networkState == NETWORK_EMPTY || m_completelyLoaded || m_isFinalizing)
-        return;
-
-    // 2 - Set the error attribute to a new MediaError object whose code attribute is set to MEDIA_ERR_ABORTED.
-    m_error = MediaError::create(MediaError::MEDIA_ERR_ABORTED);
-
-    // 3 - Queue a task to fire a simple event named error at the media element.
-    scheduleEvent(EventTypeNames::abort);
-
-    // 4 - If the media element's readyState attribute has a value equal to HAVE_NOTHING, set the
-    // element's networkState attribute to the NETWORK_EMPTY value and queue a task to fire a
-    // simple event named emptied at the element. Otherwise, set the element's networkState
-    // attribute to the NETWORK_IDLE value.
-    if (readyState == HAVE_NOTHING) {
-        setNetworkState(NETWORK_EMPTY);
-        scheduleEvent(EventTypeNames::emptied);
-    } else {
-        setNetworkState(NETWORK_IDLE);
-    }
-
-    // 5 - Set the element's delaying-the-load-event flag to false. This stops delaying the load event.
-    setShouldDelayLoadEvent(false);
-
-    // 6 - Abort the overall resource selection algorithm.
-    m_currentSourceNode = nullptr;
-
-    invalidateCachedTime();
-    cueTimeline().updateActiveCues(0);
-}
-
 void HTMLMediaElement::clearMediaPlayerAndAudioSourceProviderClientWithoutLocking()
 {
 #if ENABLE(WEB_AUDIO)
@@ -3070,13 +3021,19 @@
 
     recordMetricsIfPausing();
 
-    // Close the async event queue so that no events are enqueued by userCancelledLoad.
+    // Close the async event queue so that no events are enqueued.
     cancelPendingEventsAndCallbacks();
     m_asyncEventQueue->close();
 
-    userCancelledLoad();
-
     // Stop the playback without generating events
+    clearMediaPlayer(-1);
+    m_readyState = HAVE_NOTHING;
+    m_readyStateMaximum = HAVE_NOTHING;
+    setNetworkState(NETWORK_EMPTY);
+    setShouldDelayLoadEvent(false);
+    m_currentSourceNode = nullptr;
+    invalidateCachedTime();
+    cueTimeline().updateActiveCues(0);
     m_playing = false;
     m_paused = true;
     m_seeking = false;
diff --git a/third_party/WebKit/Source/core/html/HTMLMediaElement.h b/third_party/WebKit/Source/core/html/HTMLMediaElement.h
index e1c6785..45d33451 100644
--- a/third_party/WebKit/Source/core/html/HTMLMediaElement.h
+++ b/third_party/WebKit/Source/core/html/HTMLMediaElement.h
@@ -356,7 +356,6 @@
     WebMediaPlayer::LoadType loadType() const;
     void scheduleNextSourceChild();
     void loadNextSourceChild();
-    void userCancelledLoad();
     void clearMediaPlayer(int flags);
     void clearMediaPlayerAndAudioSourceProviderClientWithoutLocking();
     bool havePotentialSourceChild();
diff --git a/third_party/WebKit/Source/core/html/HTMLOptionElement.cpp b/third_party/WebKit/Source/core/html/HTMLOptionElement.cpp
index c94e8f47..8594640e7 100644
--- a/third_party/WebKit/Source/core/html/HTMLOptionElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLOptionElement.cpp
@@ -213,8 +213,8 @@
                 LayoutTheme::theme().controlStateChanged(*layoutObject(), EnabledControlState);
         }
     } else if (name == selectedAttr) {
-        if (bool willBeSelected = !value.isNull())
-            setSelected(willBeSelected);
+        if (oldValue.isNull() != value.isNull() && !m_isDirty)
+            setSelected(!value.isNull());
     } else if (name == labelAttr) {
         updateLabel();
     } else {
@@ -263,6 +263,17 @@
         select->optionSelectionStateChanged(this, selected);
 }
 
+bool HTMLOptionElement::selectedForBinding() const
+{
+    return selected();
+}
+
+void HTMLOptionElement::setSelectedForBinding(bool selected)
+{
+    setSelected(selected);
+    m_isDirty = true;
+}
+
 void HTMLOptionElement::setSelectedState(bool selected)
 {
     if (m_isSelected == selected)
@@ -286,6 +297,11 @@
     }
 }
 
+void HTMLOptionElement::setDirty(bool value)
+{
+    m_isDirty = true;
+}
+
 void HTMLOptionElement::childrenChanged(const ChildrenChange& change)
 {
     if (HTMLDataListElement* dataList = ownerDataListElement())
diff --git a/third_party/WebKit/Source/core/html/HTMLOptionElement.h b/third_party/WebKit/Source/core/html/HTMLOptionElement.h
index 88ca48a..cb509cf 100644
--- a/third_party/WebKit/Source/core/html/HTMLOptionElement.h
+++ b/third_party/WebKit/Source/core/html/HTMLOptionElement.h
@@ -58,6 +58,8 @@
 
     bool selected() const;
     void setSelected(bool);
+    bool selectedForBinding() const;
+    void setSelectedForBinding(bool);
 
     HTMLDataListElement* ownerDataListElement() const;
     HTMLSelectElement* ownerSelectElement() const;
@@ -71,7 +73,10 @@
 
     String textIndentedToRespectGroupLabel() const;
 
+    // Update 'selectedness'.
     void setSelectedState(bool);
+    // Update 'dirtiness'.
+    void setDirty(bool);
 
     HTMLFormElement* form() const;
     bool spatialNavigationFocused() const;
@@ -104,7 +109,12 @@
     void updateLabel();
 
     bool m_disabled;
+    // Represents 'selectedness'.
+    // https://html.spec.whatwg.org/multipage/forms.html#concept-option-selectedness
     bool m_isSelected;
+    // Represents 'dirtiness'.
+    // https://html.spec.whatwg.org/multipage/forms.html#concept-option-dirtiness
+    bool m_isDirty = false;
     RefPtr<ComputedStyle> m_style;
 };
 
diff --git a/third_party/WebKit/Source/core/html/HTMLOptionElement.idl b/third_party/WebKit/Source/core/html/HTMLOptionElement.idl
index bcbeed3..92a23236 100644
--- a/third_party/WebKit/Source/core/html/HTMLOptionElement.idl
+++ b/third_party/WebKit/Source/core/html/HTMLOptionElement.idl
@@ -32,7 +32,7 @@
     readonly attribute HTMLFormElement? form;
     attribute DOMString label;
     [Reflect=selected] attribute boolean defaultSelected;
-    attribute boolean selected;
+    [ImplementedAs=selectedForBinding] attribute boolean selected;
     attribute DOMString value;
 
     // TODO(philipj): The text setter should never throw.
diff --git a/third_party/WebKit/Source/core/html/HTMLSelectElement.cpp b/third_party/WebKit/Source/core/html/HTMLSelectElement.cpp
index dc1c7de..8dd4727 100644
--- a/third_party/WebKit/Source/core/html/HTMLSelectElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLSelectElement.cpp
@@ -143,7 +143,7 @@
     if (optionIndex == selectedIndex())
         return;
 
-    selectOption(optionIndex, DeselectOtherOptions | (fireOnChangeNow ? DispatchInputAndChangeEvent : 0));
+    selectOption(optionIndex, DeselectOtherOptions | MakeOptionDirty | (fireOnChangeNow ? DispatchInputAndChangeEvent : 0));
 }
 
 bool HTMLSelectElement::hasPlaceholderLabelOption() const
@@ -282,7 +282,7 @@
     setSuggestedIndex(-1);
     if (m_isAutofilledByPreview)
         setAutofilled(false);
-    SelectOptionFlags flags = DeselectOtherOptions;
+    SelectOptionFlags flags = DeselectOtherOptions | MakeOptionDirty;
     if (sendEvents)
         flags |= DispatchInputAndChangeEvent;
     selectOption(optionIndex, flags);
@@ -447,7 +447,7 @@
     // Restore selectedIndex after changing the multiple flag to preserve
     // selection as single-line and multi-line has different defaults.
     if (oldMultiple != this->multiple())
-        setSelectedIndex(oldSelectedIndex);
+        selectOption(oldSelectedIndex, DeselectOtherOptions);
 }
 
 void HTMLSelectElement::setSize(unsigned size)
@@ -679,16 +679,20 @@
 
     const WillBeHeapVector<RawPtrWillBeMember<HTMLElement>>& items = listItems();
     for (int i = 0; i < static_cast<int>(items.size()); ++i) {
-        HTMLElement* element = items[i];
-        if (!isHTMLOptionElement(*element) || toHTMLOptionElement(element)->isDisabledFormControl() || !toHTMLOptionElement(element)->layoutObject())
+        if (!isHTMLOptionElement(*items[i]))
             continue;
-
-        if (i >= start && i <= end)
-            toHTMLOptionElement(element)->setSelectedState(m_activeSelectionState);
-        else if (deselectOtherOptions || i >= static_cast<int>(m_cachedStateForActiveSelection.size()))
-            toHTMLOptionElement(element)->setSelectedState(false);
-        else
-            toHTMLOptionElement(element)->setSelectedState(m_cachedStateForActiveSelection[i]);
+        HTMLOptionElement& option = toHTMLOptionElement(*items[i]);
+        if (option.isDisabledFormControl() || !option.layoutObject())
+            continue;
+        if (i >= start && i <= end) {
+            option.setSelectedState(m_activeSelectionState);
+            option.setDirty(true);
+        } else if (deselectOtherOptions || i >= static_cast<int>(m_cachedStateForActiveSelection.size())) {
+            option.setSelectedState(false);
+            option.setDirty(true);
+        } else {
+            option.setSelectedState(m_cachedStateForActiveSelection[i]);
+        }
     }
 
     setNeedsValidityCheck();
@@ -899,7 +903,7 @@
 
 void HTMLSelectElement::setSelectedIndex(int index)
 {
-    selectOption(index, DeselectOtherOptions);
+    selectOption(index, DeselectOtherOptions | MakeOptionDirty);
 }
 
 int HTMLSelectElement::suggestedIndex() const
@@ -1009,6 +1013,8 @@
         // because optionToListIndex() returned it.
         element = toHTMLOptionElement(items[listIndex]);
         element->setSelectedState(true);
+        if (flags & MakeOptionDirty)
+            element->setDirty(true);
     }
 
     // deselectItemsWithoutValidation() is O(N).
@@ -1171,10 +1177,13 @@
         size_t index = state[1].toUInt();
         if (index < itemsSize && isHTMLOptionElement(items[index]) && toHTMLOptionElement(items[index])->value() == state[0]) {
             toHTMLOptionElement(items[index])->setSelectedState(true);
+            toHTMLOptionElement(items[index])->setDirty(true);
         } else {
             size_t foundIndex = searchOptionsForValue(state[0], 0, itemsSize);
-            if (foundIndex != kNotFound)
+            if (foundIndex != kNotFound) {
                 toHTMLOptionElement(items[foundIndex])->setSelectedState(true);
+                toHTMLOptionElement(items[foundIndex])->setDirty(true);
+            }
         }
     } else {
         size_t startIndex = 0;
@@ -1183,6 +1192,7 @@
             const size_t index = state[i + 1].toUInt();
             if (index < itemsSize && isHTMLOptionElement(items[index]) && toHTMLOptionElement(items[index])->value() == value) {
                 toHTMLOptionElement(items[index])->setSelectedState(true);
+                toHTMLOptionElement(items[index])->setDirty(true);
                 startIndex = index + 1;
             } else {
                 size_t foundIndex = searchOptionsForValue(value, startIndex, itemsSize);
@@ -1191,6 +1201,7 @@
                 if (foundIndex == kNotFound)
                     continue;
                 toHTMLOptionElement(items[foundIndex])->setSelectedState(true);
+                toHTMLOptionElement(items[foundIndex])->setDirty(true);
                 startIndex = foundIndex + 1;
             }
         }
@@ -1229,21 +1240,21 @@
 
     const WillBeHeapVector<RawPtrWillBeMember<HTMLElement>>& items = listItems();
     for (unsigned i = 0; i < items.size(); ++i) {
-        HTMLElement* element = items[i];
-        if (!isHTMLOptionElement(*element))
+        if (!isHTMLOptionElement(*items[i]))
             continue;
-
-        if (items[i]->fastHasAttribute(selectedAttr)) {
+        HTMLOptionElement* option = toHTMLOptionElement(items[i]);
+        if (option->fastHasAttribute(selectedAttr)) {
             if (selectedOption && !m_multiple)
                 selectedOption->setSelectedState(false);
-            toHTMLOptionElement(element)->setSelectedState(true);
-            selectedOption = toHTMLOptionElement(element);
+            option->setSelectedState(true);
+            selectedOption = option;
         } else {
-            toHTMLOptionElement(element)->setSelectedState(false);
+            option->setSelectedState(false);
         }
+        option->setDirty(false);
 
         if (!firstOption)
-            firstOption = toHTMLOptionElement(element);
+            firstOption = option;
     }
 
     if (!selectedOption && firstOption && !m_multiple && m_size <= 1)
@@ -1338,7 +1349,7 @@
             handled = false;
 
         if (handled && static_cast<size_t>(listIndex) < listItems.size())
-            selectOption(listToOptionIndex(listIndex), DeselectOtherOptions | DispatchInputAndChangeEvent);
+            selectOption(listToOptionIndex(listIndex), DeselectOtherOptions | MakeOptionDirty | DispatchInputAndChangeEvent);
 
         if (handled)
             event->setDefaultHandled();
@@ -1415,12 +1426,14 @@
     bool multiSelect = m_multiple && multi && !shift;
 
     if (isHTMLOptionElement(*clickedElement)) {
+        HTMLOptionElement& option = toHTMLOptionElement(*clickedElement);
         // Keep track of whether an active selection (like during drag
         // selection), should select or deselect.
-        if (toHTMLOptionElement(*clickedElement).selected() && multiSelect)
+        if (option.selected() && multiSelect) {
             m_activeSelectionState = false;
-        if (!m_activeSelectionState)
-            toHTMLOptionElement(*clickedElement).setSelectedState(false);
+            option.setSelectedState(false);
+            option.setDirty(true);
+        }
     }
 
     // If we're not in any special multiple selection mode, then deselect all
@@ -1435,8 +1448,10 @@
         setActiveSelectionAnchorIndex(selectedIndex());
 
     // Set the selection state of the clicked option.
-    if (isHTMLOptionElement(*clickedElement) && !toHTMLOptionElement(*clickedElement).isDisabledFormControl())
+    if (isHTMLOptionElement(*clickedElement) && !toHTMLOptionElement(*clickedElement).isDisabledFormControl()) {
         toHTMLOptionElement(*clickedElement).setSelectedState(true);
+        toHTMLOptionElement(*clickedElement).setDirty(true);
+    }
 
     // If there was no selectedIndex() for the previous initialization, or If
     // we're doing a single selection, or a multiple selection (using cmd or
@@ -1725,7 +1740,7 @@
     int index = m_typeAhead.handleEvent(event, TypeAhead::MatchPrefix | TypeAhead::CycleFirstChar);
     if (index < 0)
         return;
-    selectOption(listToOptionIndex(index), DeselectOtherOptions | DispatchInputAndChangeEvent);
+    selectOption(listToOptionIndex(index), DeselectOtherOptions | MakeOptionDirty | DispatchInputAndChangeEvent);
     if (!usesMenuList())
         listBoxOnChange();
 }
@@ -1754,6 +1769,7 @@
     } else {
         selectOption(index, DispatchInputAndChangeEvent);
     }
+    toHTMLOptionElement(element).setDirty(true);
     if (usesMenuList())
         return;
     listBoxOnChange();
diff --git a/third_party/WebKit/Source/core/html/HTMLSelectElement.h b/third_party/WebKit/Source/core/html/HTMLSelectElement.h
index 06287eff..afb46724 100644
--- a/third_party/WebKit/Source/core/html/HTMLSelectElement.h
+++ b/third_party/WebKit/Source/core/html/HTMLSelectElement.h
@@ -208,6 +208,7 @@
     enum SelectOptionFlag {
         DeselectOtherOptions = 1 << 0,
         DispatchInputAndChangeEvent = 1 << 1,
+        MakeOptionDirty = 1 << 2,
     };
     typedef unsigned SelectOptionFlags;
     void selectOption(int optionIndex, SelectOptionFlags = 0);
diff --git a/third_party/WebKit/Source/core/html/HTMLTextFormControlElementTest.cpp b/third_party/WebKit/Source/core/html/HTMLTextFormControlElementTest.cpp
index 2ff8c82..590560d9 100644
--- a/third_party/WebKit/Source/core/html/HTMLTextFormControlElementTest.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLTextFormControlElementTest.cpp
@@ -47,24 +47,16 @@
     RefPtrWillBePersistent<HTMLInputElement> m_input;
 };
 
-class DummyTextCheckerClient : public EmptyTextCheckerClient {
-public:
-    ~DummyTextCheckerClient() { }
-
-    bool shouldEraseMarkersAfterChangeSelection(TextCheckingType) const override { return false; }
-};
-
 class DummySpellCheckerClient : public EmptySpellCheckerClient {
 public:
     virtual ~DummySpellCheckerClient() { }
 
     bool isContinuousSpellCheckingEnabled() override { return true; }
-    bool isGrammarCheckingEnabled() override { return true; }
 
-    TextCheckerClient& textChecker() override { return m_dummyTextCheckerClient; }
+    TextCheckerClient& textChecker() override { return m_emptyTextCheckerClient; }
 
 private:
-    DummyTextCheckerClient m_dummyTextCheckerClient;
+    EmptyTextCheckerClient m_emptyTextCheckerClient;
 };
 
 void HTMLTextFormControlElementTest::SetUp()
diff --git a/third_party/WebKit/Source/core/html/HTMLTrackElement.h b/third_party/WebKit/Source/core/html/HTMLTrackElement.h
index 19beb53c..8d1d1990 100644
--- a/third_party/WebKit/Source/core/html/HTMLTrackElement.h
+++ b/third_party/WebKit/Source/core/html/HTMLTrackElement.h
@@ -72,7 +72,6 @@
     void newCuesAvailable(TextTrackLoader*) override;
     void cueLoadingCompleted(TextTrackLoader*, bool loadingFailed) override;
     void newRegionsAvailable(TextTrackLoader*) override;
-    String debugName() const override { return "HTMLTrackElement"; }
 
     void setReadyState(ReadyState);
 
diff --git a/third_party/WebKit/Source/core/html/PluginDocument.cpp b/third_party/WebKit/Source/core/html/PluginDocument.cpp
index dc40f1c5..b10bfbf 100644
--- a/third_party/WebKit/Source/core/html/PluginDocument.cpp
+++ b/third_party/WebKit/Source/core/html/PluginDocument.cpp
@@ -135,14 +135,7 @@
 
 void PluginDocumentParser::finish()
 {
-    if (PluginView* view = pluginView()) {
-        const ResourceError& error = document()->loader()->mainDocumentError();
-        if (error.isNull())
-            view->didFinishLoading();
-        else
-            view->didFailLoading(error);
-        m_embedElement = nullptr;
-    }
+    m_embedElement = nullptr;
     RawDataDocumentParser::finish();
 }
 
diff --git a/third_party/WebKit/Source/core/html/shadow/MediaControlElementTypes.cpp b/third_party/WebKit/Source/core/html/shadow/MediaControlElementTypes.cpp
index 9edb2ad..2ea2f3d 100644
--- a/third_party/WebKit/Source/core/html/shadow/MediaControlElementTypes.cpp
+++ b/third_party/WebKit/Source/core/html/shadow/MediaControlElementTypes.cpp
@@ -97,6 +97,8 @@
 
 void MediaControlElement::setIsWanted(bool wanted)
 {
+    if (m_isWanted == wanted)
+        return;
     m_isWanted = wanted;
     updateShownState();
 }
diff --git a/third_party/WebKit/Source/core/imagebitmap/ImageBitmapFactories.idl b/third_party/WebKit/Source/core/imagebitmap/ImageBitmapFactories.idl
index a94b9922..fa642d1 100644
--- a/third_party/WebKit/Source/core/imagebitmap/ImageBitmapFactories.idl
+++ b/third_party/WebKit/Source/core/imagebitmap/ImageBitmapFactories.idl
@@ -28,6 +28,8 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+// https://html.spec.whatwg.org/#imagebitmapfactories
+
 typedef (HTMLImageElement or
          HTMLVideoElement or
          HTMLCanvasElement or
diff --git a/third_party/WebKit/Source/core/input/EventHandler.cpp b/third_party/WebKit/Source/core/input/EventHandler.cpp
index 444132c7..1363f3f 100644
--- a/third_party/WebKit/Source/core/input/EventHandler.cpp
+++ b/third_party/WebKit/Source/core/input/EventHandler.cpp
@@ -3200,7 +3200,7 @@
 WebInputEventResult EventHandler::keyEvent(const PlatformKeyboardEvent& initialKeyEvent)
 {
     RefPtrWillBeRawPtr<FrameView> protector(m_frame->view());
-    m_frame->chromeClient().setToolTip(String(), LTR);
+    m_frame->chromeClient().clearToolTip();
 
     if (initialKeyEvent.windowsVirtualKeyCode() == VK_CAPITAL)
         capsLockStateMayHaveChanged();
diff --git a/third_party/WebKit/Source/core/input/TouchActionUtil.cpp b/third_party/WebKit/Source/core/input/TouchActionUtil.cpp
index 8ef15dfd8..cf93a4a 100644
--- a/third_party/WebKit/Source/core/input/TouchActionUtil.cpp
+++ b/third_party/WebKit/Source/core/input/TouchActionUtil.cpp
@@ -6,6 +6,7 @@
 #include "core/input/TouchActionUtil.h"
 
 #include "core/dom/Node.h"
+#include "core/html/HTMLFrameOwnerElement.h"
 #include "core/layout/LayoutBox.h"
 #include "core/layout/LayoutObject.h"
 
@@ -18,7 +19,7 @@
 // According to the CSS Box Model Spec (http://dev.w3.org/csswg/css-box/#the-width-and-height-properties)
 // width applies to all elements but non-replaced inline elements, table rows, and row groups and
 // height applies to all elements but non-replaced inline elements, table columns, and column groups.
-static bool supportsTouchAction(const LayoutObject& object)
+bool supportsTouchAction(const LayoutObject& object)
 {
     if (object.isInline() && !object.isReplaced())
         return false;
@@ -28,26 +29,45 @@
     return true;
 }
 
+const Node* parentNodeAcrossFrames(const Node* curNode)
+{
+    Node* parentNode = ComposedTreeTraversal::parent(*curNode);
+    if (parentNode)
+        return parentNode;
+
+    if (curNode->isDocumentNode()) {
+        const Document* doc = toDocument(curNode);
+        return doc->ownerElement();
+    }
+
+    return nullptr;
+}
+
 } // namespace
 
 TouchAction computeEffectiveTouchAction(const Node& node)
 {
     // Start by permitting all actions, then walk the elements supporting
-    // touch-action from the target node up to the nearest scrollable ancestor
-    // and exclude any prohibited actions.
+    // touch-action from the target node up to root document, exclude any
+    // prohibited actions at or below the element that supports them.
+    // I.e. pan-related actions are considered up to the nearest scroller,
+    // and zoom related actions are considered up to the root.
     TouchAction effectiveTouchAction = TouchActionAuto;
-    for (const Node* curNode = &node; curNode; curNode = ComposedTreeTraversal::parent(*curNode)) {
+    TouchAction handledTouchActions = TouchActionNone;
+    for (const Node* curNode = &node; curNode; curNode = parentNodeAcrossFrames(curNode)) {
         if (LayoutObject* layoutObject = curNode->layoutObject()) {
             if (supportsTouchAction(*layoutObject)) {
                 TouchAction action = layoutObject->style()->touchAction();
+                action |= handledTouchActions;
                 effectiveTouchAction &= action;
                 if (effectiveTouchAction == TouchActionNone)
                     break;
             }
 
-            // If we've reached an ancestor that supports a touch action, search no further.
-            if (layoutObject->isBox() && toLayoutBox(layoutObject)->scrollsOverflow())
-                break;
+            // If we've reached an ancestor that supports panning, stop allowing panning to be disabled.
+            if ((layoutObject->isBox() && toLayoutBox(layoutObject)->scrollsOverflow())
+                || layoutObject->isLayoutView())
+                handledTouchActions |= TouchActionPan;
         }
     }
     return effectiveTouchAction;
diff --git a/third_party/WebKit/Source/core/inspector/v8/InspectorWrapper.cpp b/third_party/WebKit/Source/core/inspector/v8/InspectorWrapper.cpp
index 1cab1b3..a9588d6 100644
--- a/third_party/WebKit/Source/core/inspector/v8/InspectorWrapper.cpp
+++ b/third_party/WebKit/Source/core/inspector/v8/InspectorWrapper.cpp
@@ -52,8 +52,8 @@
 
 void* InspectorWrapperBase::unwrap(v8::Local<v8::Context> context, v8::Local<v8::Object> object, const char* name)
 {
-    ASSERT(context != v8::Debug::GetDebugContext());
     v8::Isolate* isolate = context->GetIsolate();
+    ASSERT(context != v8::Debug::GetDebugContext(isolate));
     v8::Local<v8::Value> value = V8HiddenValue::getHiddenValue(ScriptState::from(context), object, v8InternalizedString(isolate, name));
     if (value.IsEmpty())
         return nullptr;
diff --git a/third_party/WebKit/Source/core/inspector/v8/V8DebuggerImpl.cpp b/third_party/WebKit/Source/core/inspector/v8/V8DebuggerImpl.cpp
index fdb4be8..60ff3fe6 100644
--- a/third_party/WebKit/Source/core/inspector/v8/V8DebuggerImpl.cpp
+++ b/third_party/WebKit/Source/core/inspector/v8/V8DebuggerImpl.cpp
@@ -80,8 +80,8 @@
 {
     ASSERT(!enabled());
     v8::HandleScope scope(m_isolate);
-    v8::Debug::SetDebugEventListener(&V8DebuggerImpl::v8DebugEventCallback, v8::External::New(m_isolate, this));
-    m_debuggerContext.Reset(m_isolate, v8::Debug::GetDebugContext());
+    v8::Debug::SetDebugEventListener(m_isolate, &V8DebuggerImpl::v8DebugEventCallback, v8::External::New(m_isolate, this));
+    m_debuggerContext.Reset(m_isolate, v8::Debug::GetDebugContext(m_isolate));
     m_callFrameWrapperTemplate.Reset(m_isolate, V8JavaScriptCallFrame::createWrapperTemplate(m_isolate));
     compileDebuggerScript();
 }
@@ -93,7 +93,7 @@
     m_debuggerScript.Reset();
     m_debuggerContext.Reset();
     m_callFrameWrapperTemplate.Reset();
-    v8::Debug::SetDebugEventListener(nullptr);
+    v8::Debug::SetDebugEventListener(m_isolate, nullptr);
 }
 
 bool V8DebuggerImpl::enabled() const
@@ -192,8 +192,8 @@
     info->Set(v8InternalizedString("condition"), v8String(m_isolate, scriptBreakpoint.condition));
 
     v8::Local<v8::Function> setBreakpointFunction = v8::Local<v8::Function>::Cast(m_debuggerScript.Get(m_isolate)->Get(v8InternalizedString("setBreakpoint")));
-    v8::Local<v8::Value> breakpointId = v8::Debug::Call(setBreakpointFunction, info);
-    if (breakpointId.IsEmpty() || !breakpointId->IsString())
+    v8::Local<v8::Value> breakpointId = v8CallOrCrash(v8::Debug::Call(debuggerContext(), setBreakpointFunction, info));
+    if (!breakpointId->IsString())
         return "";
     *actualLineNumber = info->Get(v8InternalizedString("lineNumber"))->Int32Value();
     *actualColumnNumber = info->Get(v8InternalizedString("columnNumber"))->Int32Value();
@@ -209,7 +209,7 @@
     info->Set(v8InternalizedString("breakpointId"), v8String(m_isolate, breakpointId));
 
     v8::Local<v8::Function> removeBreakpointFunction = v8::Local<v8::Function>::Cast(m_debuggerScript.Get(m_isolate)->Get(v8InternalizedString("removeBreakpoint")));
-    v8::Debug::Call(removeBreakpointFunction, info);
+    v8CallOrCrash(v8::Debug::Call(debuggerContext(), removeBreakpointFunction, info));
 }
 
 void V8DebuggerImpl::clearBreakpoints()
@@ -218,7 +218,7 @@
     v8::Context::Scope contextScope(debuggerContext());
 
     v8::Local<v8::Function> clearBreakpoints = v8::Local<v8::Function>::Cast(m_debuggerScript.Get(m_isolate)->Get(v8InternalizedString("clearBreakpoints")));
-    v8::Debug::Call(clearBreakpoints);
+    v8CallOrCrash(v8::Debug::Call(debuggerContext(), clearBreakpoints));
 }
 
 void V8DebuggerImpl::setBreakpointsActivated(bool activated)
@@ -233,7 +233,7 @@
     v8::Local<v8::Object> info = v8::Object::New(m_isolate);
     info->Set(v8InternalizedString("enabled"), v8::Boolean::New(m_isolate, activated));
     v8::Local<v8::Function> setBreakpointsActivated = v8::Local<v8::Function>::Cast(m_debuggerScript.Get(m_isolate)->Get(v8InternalizedString("setBreakpointsActivated")));
-    v8::Debug::Call(setBreakpointsActivated, info);
+    v8CallOrCrash(v8::Debug::Call(debuggerContext(), setBreakpointsActivated, info));
 
     m_breakpointsActivated = activated;
 }
@@ -301,7 +301,7 @@
     }
 
     v8::Local<v8::Function> breakProgramFunction = v8::Local<v8::FunctionTemplate>::New(m_isolate, m_breakProgramCallbackTemplate)->GetFunction();
-    v8::Debug::Call(breakProgramFunction);
+    v8CallOrCrash(v8::Debug::Call(debuggerContext(), breakProgramFunction));
 }
 
 void V8DebuggerImpl::continueProgram()
@@ -447,7 +447,7 @@
     v8::Local<v8::Value> currentCallFrameV8;
     if (m_executionState.IsEmpty()) {
         v8::Local<v8::Function> currentCallFrameFunction = v8::Local<v8::Function>::Cast(m_debuggerScript.Get(m_isolate)->Get(v8InternalizedString("currentCallFrame")));
-        currentCallFrameV8 = v8::Debug::Call(currentCallFrameFunction, v8::Integer::New(m_isolate, data));
+        currentCallFrameV8 = v8CallOrCrash(v8::Debug::Call(debuggerContext(), currentCallFrameFunction, v8::Integer::New(m_isolate, data)));
     } else {
         v8::Local<v8::Value> argv[] = { m_executionState, v8::Integer::New(m_isolate, data) };
         currentCallFrameV8 = callDebuggerMethod("currentCallFrame", WTF_ARRAY_LENGTH(argv), argv).ToLocalChecked();
@@ -498,7 +498,7 @@
     v8::Local<v8::Value> currentCallFrameV8;
     if (m_executionState.IsEmpty()) {
         v8::Local<v8::Function> currentCallFrameFunction = v8::Local<v8::Function>::Cast(m_debuggerScript.Get(m_isolate)->Get(v8InternalizedString("currentCallFrameByIndex")));
-        currentCallFrameV8 = v8::Debug::Call(currentCallFrameFunction, v8::Integer::New(m_isolate, index));
+        currentCallFrameV8 = v8CallOrCrash(v8::Debug::Call(debuggerContext(), currentCallFrameFunction, v8::Integer::New(m_isolate, index)));
     } else {
         v8::Local<v8::Value> argv[] = { m_executionState, v8::Integer::New(m_isolate, index) };
         currentCallFrameV8 = callDebuggerMethod("currentCallFrameByIndex", WTF_ARRAY_LENGTH(argv), argv).ToLocalChecked();
diff --git a/third_party/WebKit/Source/core/layout/LayoutBlock.cpp b/third_party/WebKit/Source/core/layout/LayoutBlock.cpp
index 0a7572f..c4299e3 100644
--- a/third_party/WebKit/Source/core/layout/LayoutBlock.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutBlock.cpp
@@ -618,12 +618,9 @@
         return;
 
     Vector<LayoutBlock*, 3> blocksToRemove;
-    Vector<LayoutBox*, 16> floatsToRemoveFromFloatLists;
     for (LayoutObject* child = firstChild(); child; child = child->nextSibling()) {
-        if (child->isFloating()) {
-            floatsToRemoveFromFloatLists.append(toLayoutBox(child));
+        if (child->isFloating())
             continue;
-        }
         if (child->isOutOfFlowPositioned())
             continue;
 
@@ -648,10 +645,9 @@
     }
 
     // If we make an object's children inline we are going to frustrate any future attempts to remove
-    // floats from its children's float-lists before the next layout happens so remove them proactively here.
-    // TODO(rhogan): We need to understand if intruding floats in this object's float list need to be removed also.
-    for (size_t i = 0; i < floatsToRemoveFromFloatLists.size(); i++)
-        toLayoutBlockFlow(this)->markAllDescendantsWithFloatsForLayout(floatsToRemoveFromFloatLists[i]);
+    // floats from its children's float-lists before the next layout happens so clear down all the floatlists
+    // now - they will be rebuilt at layout.
+    toLayoutBlockFlow(this)->removeFloatingObjectsFromDescendants();
 
     for (size_t i = 0; i < blocksToRemove.size(); i++)
         collapseAnonymousBlockChild(this, blocksToRemove[i]);
diff --git a/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp b/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp
index 5438572..b83ced6 100644
--- a/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp
@@ -1745,6 +1745,24 @@
     m_lineBoxes.deleteLineBoxTree();
 }
 
+void LayoutBlockFlow::removeFloatingObjectsFromDescendants()
+{
+    if (!containsFloats())
+        return;
+    removeFloatingObjects();
+
+    // If our children are inline, then the only boxes which could contain floats are atomic inlines (e.g. inline-block, float etc.)
+    // and these create formatting contexts, so can't pick up intruding floats from ancestors/siblings - making them safe to skip.
+    if (childrenInline())
+        return;
+    for (LayoutObject* child = firstChild(); child; child = child->nextSibling()) {
+        // We don't skip blocks that create formatting contexts as they may have only recently
+        // changed style and their float lists may still contain floats from siblings and ancestors.
+        if (child->isLayoutBlockFlow())
+            toLayoutBlockFlow(child)->removeFloatingObjectsFromDescendants();
+    }
+}
+
 void LayoutBlockFlow::markAllDescendantsWithFloatsForLayout(LayoutBox* floatToRemove, bool inLayout)
 {
     if (!everHadLayout() && !containsFloats())
@@ -1763,7 +1781,6 @@
     // Iterate over our children and mark them as needed. If our children are inline, then the
     // only boxes which could contain floats are atomic inlines (e.g. inline-block, float etc.) and these create formatting
     // contexts, so can't pick up intruding floats from ancestors/siblings - making them safe to skip.
-    // TODO(rhogan): Should this be !createsNewFormattingContext() instead of !childrenInline()?
     if (!childrenInline()) {
         for (LayoutObject* child = firstChild(); child; child = child->nextSibling()) {
             if ((!floatToRemove && child->isFloatingOrOutOfFlowPositioned()) || !child->isLayoutBlock())
diff --git a/third_party/WebKit/Source/core/layout/LayoutBlockFlow.h b/third_party/WebKit/Source/core/layout/LayoutBlockFlow.h
index 36120f88..61057fe8 100644
--- a/third_party/WebKit/Source/core/layout/LayoutBlockFlow.h
+++ b/third_party/WebKit/Source/core/layout/LayoutBlockFlow.h
@@ -133,6 +133,7 @@
 
     RootInlineBox* createAndAppendRootInlineBox();
 
+    void removeFloatingObjectsFromDescendants();
     void markAllDescendantsWithFloatsForLayout(LayoutBox* floatToRemove = nullptr, bool inLayout = true);
     void markSiblingsWithFloatsForLayout(LayoutBox* floatToRemove = nullptr);
 
diff --git a/third_party/WebKit/Source/core/layout/LayoutBox.cpp b/third_party/WebKit/Source/core/layout/LayoutBox.cpp
index 029dc87c..4a51e69 100644
--- a/third_party/WebKit/Source/core/layout/LayoutBox.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutBox.cpp
@@ -2362,7 +2362,7 @@
         // grab our cached flexible height.
         // FIXME: Account for writing-mode in flexible boxes.
         // https://bugs.webkit.org/show_bug.cgi?id=46418
-        if (hasOverrideLogicalContentHeight() && (parent()->isFlexibleBoxIncludingDeprecated() || parent()->isLayoutGrid())) {
+        if (hasOverrideLogicalContentHeight()) {
             LayoutUnit contentHeight = overrideLogicalContentHeight();
             if (parent()->isLayoutGrid() && style()->logicalMinHeight().isAuto() && style()->overflowY() == OVISIBLE) {
                 ASSERT(style()->logicalHeight().isAuto());
diff --git a/third_party/WebKit/Source/core/layout/LayoutMultiColumnSpannerPlaceholder.cpp b/third_party/WebKit/Source/core/layout/LayoutMultiColumnSpannerPlaceholder.cpp
index 327edd8..1da77af 100644
--- a/third_party/WebKit/Source/core/layout/LayoutMultiColumnSpannerPlaceholder.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutMultiColumnSpannerPlaceholder.cpp
@@ -91,6 +91,11 @@
 {
     ASSERT(needsLayout());
 
+    // The placeholder, like any other block level object, has its logical top calculated and set
+    // before layout. Copy this to the actual column-span:all object before laying it out, so that
+    // it gets paginated correctly, in case we have an enclosing fragmentation context.
+    m_layoutObjectInFlowThread->setLogicalTop(logicalTop());
+
     // Lay out the actual column-span:all element.
     m_layoutObjectInFlowThread->layoutIfNeeded();
 
diff --git a/third_party/WebKit/Source/core/layout/LayoutObject.cpp b/third_party/WebKit/Source/core/layout/LayoutObject.cpp
index 21e6e9c..a92baefe 100644
--- a/third_party/WebKit/Source/core/layout/LayoutObject.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutObject.cpp
@@ -2696,7 +2696,7 @@
     setIsDragging(dragOn);
     if (valueChanged && node()) {
         if (node()->isElementNode() && toElement(node())->childrenOrSiblingsAffectedByDrag())
-            document().styleEngine().pseudoStateChangedForElement(CSSSelector::PseudoDrag, *toElement(node()));
+            toElement(node())->pseudoStateChanged(CSSSelector::PseudoDrag);
         else if (style()->affectedByDrag())
             node()->setNeedsStyleRecalc(LocalStyleChange, StyleChangeReasonForTracing::create(StyleChangeReason::Drag));
     }
diff --git a/third_party/WebKit/Source/core/layout/LayoutState.cpp b/third_party/WebKit/Source/core/layout/LayoutState.cpp
index bedcbad2..64a5004 100644
--- a/third_party/WebKit/Source/core/layout/LayoutState.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutState.cpp
@@ -52,7 +52,7 @@
 {
     if (layoutObject.isLayoutFlowThread())
         m_flowThread = toLayoutFlowThread(&layoutObject);
-    else if (!layoutObject.isOutOfFlowPositioned() && !layoutObject.isColumnSpanAll())
+    else if (!layoutObject.isOutOfFlowPositioned())
         m_flowThread = m_next->flowThread();
     else
         m_flowThread = nullptr;
diff --git a/third_party/WebKit/Source/core/layout/LayoutTestHelper.cpp b/third_party/WebKit/Source/core/layout/LayoutTestHelper.cpp
index 83dace3..97db2f3d 100644
--- a/third_party/WebKit/Source/core/layout/LayoutTestHelper.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutTestHelper.cpp
@@ -6,30 +6,24 @@
 #include "core/layout/LayoutTestHelper.h"
 
 #include "core/frame/FrameHost.h"
-#include "platform/graphics/GraphicsLayer.h"
-#include "platform/graphics/GraphicsLayerFactory.h"
+#include "platform/graphics/test/FakeGraphicsLayerFactory.h"
 
 namespace blink {
 
-class FakeGraphicsLayerFactory : public GraphicsLayerFactory {
-public:
-    PassOwnPtr<GraphicsLayer> createGraphicsLayer(GraphicsLayerClient* client) override
-    {
-        return adoptPtr(new GraphicsLayer(client));
-    }
-};
+namespace {
 
 class FakeChromeClient : public EmptyChromeClient {
 public:
     static PassOwnPtrWillBeRawPtr<FakeChromeClient> create() { return adoptPtrWillBeNoop(new FakeChromeClient); }
 
-    virtual GraphicsLayerFactory* graphicsLayerFactory() const
+    GraphicsLayerFactory* graphicsLayerFactory() const override
     {
-        static FakeGraphicsLayerFactory* factory = adoptPtr(new FakeGraphicsLayerFactory).leakPtr();
-        return factory;
+        return FakeGraphicsLayerFactory::instance();
     }
 };
 
+} // namespace
+
 RenderingTest::RenderingTest(PassOwnPtrWillBeRawPtr<FrameLoaderClient> frameLoaderClient)
 {
     Page::PageClients pageClients;
diff --git a/third_party/WebKit/Source/core/layout/LayoutTextControlSingleLine.cpp b/third_party/WebKit/Source/core/layout/LayoutTextControlSingleLine.cpp
index 73bc95d9..d23c798 100644
--- a/third_party/WebKit/Source/core/layout/LayoutTextControlSingleLine.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutTextControlSingleLine.cpp
@@ -121,19 +121,26 @@
     LayoutBox* viewPortLayoutObject = editingViewPortElement() ? editingViewPortElement()->layoutBox() : 0;
 
     // To ensure consistency between layouts, we need to reset any conditionally overriden height.
-    if (innerEditorLayoutObject && !innerEditorLayoutObject->styleRef().logicalHeight().isAuto()) {
-        innerEditorLayoutObject->mutableStyleRef().setLogicalHeight(Length(Auto));
+    if (innerEditorLayoutObject) {
+        innerEditorLayoutObject->clearOverrideLogicalContentHeight();
+        // TODO(jchaffraix): We could probably skip some of these due to
+        // forcing children relayout below but keeping them for safety for now.
         layoutScope.setNeedsLayout(innerEditorLayoutObject, LayoutInvalidationReason::TextControlChanged);
         HTMLElement* placeholderElement = inputElement()->placeholderElement();
         if (LayoutBox* placeholderBox = placeholderElement ? placeholderElement->layoutBox() : 0)
             layoutScope.setNeedsLayout(placeholderBox, LayoutInvalidationReason::TextControlChanged);
     }
+    // TODO(jchaffraix): This logic is not correct and will yield to bugs such
+    // as crbug.com/529252. The fix is similar to what is done with
+    // innerEditorLayoutObject above.
     if (viewPortLayoutObject && !viewPortLayoutObject->styleRef().logicalHeight().isAuto()) {
         viewPortLayoutObject->mutableStyleRef().setLogicalHeight(Length(Auto));
         layoutScope.setNeedsLayout(viewPortLayoutObject, LayoutInvalidationReason::TextControlChanged);
     }
 
-    LayoutBlockFlow::layoutBlock(false);
+    // This is the measuring phase. Thus we force children to be relayout so
+    // that the checks below are executed consistently.
+    LayoutBlockFlow::layoutBlock(true);
 
     Element* container = containerElement();
     LayoutBox* containerLayoutObject = container ? container->layoutBox() : 0;
@@ -147,7 +154,7 @@
 
         m_desiredInnerEditorLogicalHeight = desiredLogicalHeight;
 
-        innerEditorLayoutObject->mutableStyleRef().setLogicalHeight(Length(desiredLogicalHeight, Fixed));
+        innerEditorLayoutObject->setOverrideLogicalContentHeight(desiredLogicalHeight);
         layoutScope.setNeedsLayout(innerEditorLayoutObject, LayoutInvalidationReason::TextControlChanged);
         if (viewPortLayoutObject) {
             viewPortLayoutObject->mutableStyleRef().setLogicalHeight(Length(desiredLogicalHeight, Fixed));
@@ -252,9 +259,6 @@
         containerLayoutObject->mutableStyleRef().setHeight(Length());
         containerLayoutObject->mutableStyleRef().setWidth(Length());
     }
-    LayoutObject* innerEditorLayoutObject = innerEditorElement()->layoutObject();
-    if (innerEditorLayoutObject && diff.needsFullLayout())
-        innerEditorLayoutObject->setNeedsLayoutAndFullPaintInvalidation(LayoutInvalidationReason::StyleChange);
     if (HTMLElement* placeholder = inputElement()->placeholderElement())
         placeholder->setInlineStyleProperty(CSSPropertyTextOverflow, textShouldBeTruncated() ? CSSValueEllipsis : CSSValueClip);
     setHasOverflowClip(false);
diff --git a/third_party/WebKit/Source/core/loader/DocumentLoader.cpp b/third_party/WebKit/Source/core/loader/DocumentLoader.cpp
index 245b086..a5df91f 100644
--- a/third_party/WebKit/Source/core/loader/DocumentLoader.cpp
+++ b/third_party/WebKit/Source/core/loader/DocumentLoader.cpp
@@ -37,6 +37,7 @@
 #include "core/fetch/CSSStyleSheetResource.h"
 #include "core/fetch/FetchInitiatorTypeNames.h"
 #include "core/fetch/FetchRequest.h"
+#include "core/fetch/FontResource.h"
 #include "core/fetch/ImageResource.h"
 #include "core/fetch/MemoryCache.h"
 #include "core/fetch/ResourceFetcher.h"
@@ -161,7 +162,6 @@
 
 void DocumentLoader::startPreload(Resource::Type type, FetchRequest& request)
 {
-    ASSERT(type == Resource::Script || type == Resource::CSSStyleSheet || type == Resource::Image || type == Resource::ImportResource);
     ResourcePtr<Resource> resource;
     switch (type) {
     case Resource::Image:
@@ -173,9 +173,23 @@
     case Resource::CSSStyleSheet:
         resource = CSSStyleSheetResource::fetch(request, fetcher());
         break;
-    default: // Resource::ImportResource
+    case Resource::Font:
+        resource = FontResource::fetch(request, fetcher());
+        break;
+    case Resource::Media:
+        resource = RawResource::fetchMedia(request, fetcher());
+        break;
+    case Resource::TextTrack:
+        resource = RawResource::fetchTextTrack(request, fetcher());
+        break;
+    case Resource::ImportResource:
         resource = RawResource::fetchImport(request, fetcher());
         break;
+    case Resource::LinkSubresource:
+        resource = RawResource::fetch(request, fetcher());
+        break;
+    default:
+        ASSERT_NOT_REACHED();
     }
 
     if (resource)
@@ -217,7 +231,6 @@
         m_applicationCacheHost->failedLoadingMainResource();
     if (!frameLoader())
         return;
-    m_mainDocumentError = error;
     if (m_state < MainResourceDone)
         m_state = MainResourceDone;
     frameLoader()->receivedMainResourceError(this, error);
@@ -723,7 +736,6 @@
 void DocumentLoader::startLoadingMainResource()
 {
     RefPtrWillBeRawPtr<DocumentLoader> protect(this);
-    m_mainDocumentError = ResourceError();
     timing().markNavigationStart();
     ASSERT(!m_mainResource);
     ASSERT(m_state == NotStarted);
diff --git a/third_party/WebKit/Source/core/loader/DocumentLoader.h b/third_party/WebKit/Source/core/loader/DocumentLoader.h
index ff2d375..6b2e39c 100644
--- a/third_party/WebKit/Source/core/loader/DocumentLoader.h
+++ b/third_party/WebKit/Source/core/loader/DocumentLoader.h
@@ -98,7 +98,6 @@
     void stopLoading();
     bool isLoading() const;
     const ResourceResponse& response() const { return m_response; }
-    const ResourceError& mainDocumentError() const { return m_mainDocumentError; }
     bool isClientRedirect() const { return m_isClientRedirect; }
     void setIsClientRedirect(bool isClientRedirect) { m_isClientRedirect = isClientRedirect; }
     bool replacesCurrentHistoryItem() const { return m_replacesCurrentHistoryItem; }
@@ -213,8 +212,6 @@
 
     ResourceResponse m_response;
 
-    ResourceError m_mainDocumentError;
-
     bool m_isClientRedirect;
     bool m_replacesCurrentHistoryItem;
 
diff --git a/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.cpp b/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.cpp
index 07d88a8a..d323bb2b 100644
--- a/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.cpp
+++ b/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.cpp
@@ -288,7 +288,13 @@
 void DocumentThreadableLoader::overrideTimeout(unsigned long timeoutMilliseconds)
 {
     ASSERT(m_async);
-    ASSERT(m_requestStartedSeconds > 0.0);
+
+    // |m_requestStartedSeconds| == 0.0 indicates loading is already finished
+    // and |m_timeoutTimer| is already stopped, and thus we do nothing for such
+    // cases. See https://crbug.com/551663 for details.
+    if (m_requestStartedSeconds <= 0.0)
+        return;
+
     m_timeoutTimer.stop();
     // At the time of this method's implementation, it is only ever called by
     // XMLHttpRequest, when the timeout attribute is set after sending the
diff --git a/third_party/WebKit/Source/core/loader/EmptyClients.h b/third_party/WebKit/Source/core/loader/EmptyClients.h
index 6564317..a0ae2774 100644
--- a/third_party/WebKit/Source/core/loader/EmptyClients.h
+++ b/third_party/WebKit/Source/core/loader/EmptyClients.h
@@ -273,7 +273,6 @@
 public:
     ~EmptyTextCheckerClient() { }
 
-    bool shouldEraseMarkersAfterChangeSelection(TextCheckingType) const override { return true; }
     void checkSpellingOfString(const String&, int*, int*) override {}
     void checkGrammarOfString(const String&, Vector<GrammarDetail>&, int*, int*) override {}
     void requestCheckingOfString(PassRefPtrWillBeRawPtr<TextCheckingRequest>) override;
@@ -287,7 +286,6 @@
 
     bool isContinuousSpellCheckingEnabled() override { return false; }
     void toggleContinuousSpellChecking() override {}
-    bool isGrammarCheckingEnabled() override { return false; }
 
     TextCheckerClient& textChecker() override { return m_textCheckerClient; }
 
diff --git a/third_party/WebKit/Source/core/loader/FrameFetchContext.cpp b/third_party/WebKit/Source/core/loader/FrameFetchContext.cpp
index 273dfed..41bed10 100644
--- a/third_party/WebKit/Source/core/loader/FrameFetchContext.cpp
+++ b/third_party/WebKit/Source/core/loader/FrameFetchContext.cpp
@@ -409,7 +409,6 @@
     case Resource::Raw:
     case Resource::LinkPrefetch:
     case Resource::LinkSubresource:
-    case Resource::LinkPreload:
     case Resource::TextTrack:
     case Resource::ImportResource:
     case Resource::Media:
@@ -484,7 +483,6 @@
     case Resource::Raw:
     case Resource::LinkPrefetch:
     case Resource::LinkSubresource:
-    case Resource::LinkPreload:
         break;
     case Resource::Media:
     case Resource::TextTrack:
diff --git a/third_party/WebKit/Source/core/loader/FrameLoader.cpp b/third_party/WebKit/Source/core/loader/FrameLoader.cpp
index 0d4559b..ba674ec 100644
--- a/third_party/WebKit/Source/core/loader/FrameLoader.cpp
+++ b/third_party/WebKit/Source/core/loader/FrameLoader.cpp
@@ -996,11 +996,6 @@
     m_frame->navigationScheduler().cancel();
 
     m_inStopAllLoaders = false;
-
-    // LocalFrame::detach() can be called multiple times which
-    // means we may no longer have a FrameLoaderClient to talk to.
-    if (client())
-        client()->didStopAllLoaders();
 }
 
 void FrameLoader::didAccessInitialDocument()
@@ -1118,8 +1113,14 @@
 void FrameLoader::restoreScrollPositionAndViewState()
 {
     FrameView* view = m_frame->view();
-    if (!m_frame->page() || !view || !view->layoutViewportScrollableArea() || !m_currentItem || !m_stateMachine.committedFirstRealDocumentLoad())
+    if (!m_frame->page()
+        || !view
+        || !view->layoutViewportScrollableArea()
+        || !m_currentItem
+        || !m_stateMachine.committedFirstRealDocumentLoad()
+        || !documentLoader()) {
         return;
+    }
 
     if (!needsHistoryItemRestore(m_loadType))
         return;
diff --git a/third_party/WebKit/Source/core/loader/FrameLoader.h b/third_party/WebKit/Source/core/loader/FrameLoader.h
index b12caa89..b67c737 100644
--- a/third_party/WebKit/Source/core/loader/FrameLoader.h
+++ b/third_party/WebKit/Source/core/loader/FrameLoader.h
@@ -239,7 +239,7 @@
     RefPtrWillBeMember<HistoryItem> m_provisionalItem;
 
     class DeferredHistoryLoad : public NoBaseWillBeGarbageCollectedFinalized<DeferredHistoryLoad> {
-        DISALLOW_COPY(DeferredHistoryLoad);
+        WTF_MAKE_NONCOPYABLE(DeferredHistoryLoad);
     public:
         static PassOwnPtrWillBeRawPtr<DeferredHistoryLoad> create(ResourceRequest request, HistoryItem* item, FrameLoadType loadType, HistoryLoadType historyLoadType)
         {
diff --git a/third_party/WebKit/Source/core/loader/FrameLoaderClient.h b/third_party/WebKit/Source/core/loader/FrameLoaderClient.h
index 7fe131b2..42e507db 100644
--- a/third_party/WebKit/Source/core/loader/FrameLoaderClient.h
+++ b/third_party/WebKit/Source/core/loader/FrameLoaderClient.h
@@ -231,8 +231,6 @@
 
     virtual PassOwnPtr<WebApplicationCacheHost> createApplicationCacheHost(WebApplicationCacheHostClient*) = 0;
 
-    virtual void didStopAllLoaders() { }
-
     virtual void dispatchDidChangeManifest() { }
 
     virtual unsigned backForwardLength() { return 0; }
diff --git a/third_party/WebKit/Source/core/loader/LinkLoader.cpp b/third_party/WebKit/Source/core/loader/LinkLoader.cpp
index 6de4b8e..41d1dca 100644
--- a/third_party/WebKit/Source/core/loader/LinkLoader.cpp
+++ b/third_party/WebKit/Source/core/loader/LinkLoader.cpp
@@ -165,21 +165,23 @@
     }
 }
 
-static bool getTypeFromAsAttribute(const String& as, Resource::Type& type)
+static Resource::Type getTypeFromAsAttribute(const String& as, Document& document)
 {
-    if (as.isEmpty())
-        return false;
-
     if (equalIgnoringCase(as, "image"))
-        type = Resource::Image;
-    else if (equalIgnoringCase(as, "script"))
-        type = Resource::Script;
-    else if (equalIgnoringCase(as, "stylesheet"))
-        type = Resource::CSSStyleSheet;
-    else
-        return false;
-
-    return true;
+        return Resource::Image;
+    if (equalIgnoringCase(as, "script"))
+        return Resource::Script;
+    if (equalIgnoringCase(as, "style"))
+        return Resource::CSSStyleSheet;
+    if (equalIgnoringCase(as, "audio") || equalIgnoringCase(as, "video"))
+        return Resource::Media;
+    if (equalIgnoringCase(as, "font"))
+        return Resource::Font;
+    if (equalIgnoringCase(as, "track"))
+        return Resource::TextTrack;
+    if (!as.isEmpty())
+        document.addConsoleMessage(ConsoleMessage::create(OtherMessageSource, WarningMessageLevel, String("<link rel=preload> must have a valid `as` value")));
+    return Resource::LinkSubresource;
 }
 
 static void preloadIfNeeded(const LinkRelAttribute& relAttribute, const KURL& href, Document& document, const String& as)
@@ -194,13 +196,11 @@
             document.addConsoleMessage(ConsoleMessage::create(OtherMessageSource, WarningMessageLevel, String("<link rel=preload> has an invalid `href` value")));
             return;
         }
-        // TODO(yoav): Figure out a way that 'as' would be used to set request headers.
-        Resource::Type type;
-        if (!getTypeFromAsAttribute(as, type)) {
-            document.addConsoleMessage(ConsoleMessage::create(OtherMessageSource, WarningMessageLevel, String("<link rel=preload> must have a valid `as` value")));
-            return;
-        }
-        FetchRequest linkRequest(ResourceRequest(document.completeURL(href)), FetchInitiatorTypeNames::link);
+        Resource::Type type = getTypeFromAsAttribute(as, document);
+        ResourceRequest resourceRequest(document.completeURL(href));
+        ResourceFetcher::determineRequestContext(resourceRequest, type, false);
+        FetchRequest linkRequest(resourceRequest, FetchInitiatorTypeNames::link);
+
         linkRequest.setPriority(document.fetcher()->loadPriority(type, linkRequest));
         Settings* settings = document.settings();
         if (settings && settings->logPreload())
diff --git a/third_party/WebKit/Source/core/loader/LinkLoaderTest.cpp b/third_party/WebKit/Source/core/loader/LinkLoaderTest.cpp
index f1e04492..c4b7570dc 100644
--- a/third_party/WebKit/Source/core/loader/LinkLoaderTest.cpp
+++ b/third_party/WebKit/Source/core/loader/LinkLoaderTest.cpp
@@ -80,12 +80,22 @@
         const char* href;
         const char* as;
         const ResourceLoadPriority priority;
+        const WebURLRequest::RequestContext context;
         const bool shouldLoad;
+        const char* accept;
     } cases[] = {
-        {"data://example.test/cat.jpg", "image", ResourceLoadPriorityVeryLow, true},
-        {"data://example.test/cat.js", "script", ResourceLoadPriorityMedium, true},
-        {"data://example.test/cat.css", "stylesheet", ResourceLoadPriorityHigh, true},
-        {"data://example.test/cat.blob", "blabla", ResourceLoadPriorityUnresolved, false},
+        {"data://example.test/cat.jpg", "image", ResourceLoadPriorityVeryLow, WebURLRequest::RequestContextImage, true, "image/webp,image/*,*/*;q=0.8"},
+        {"data://example.test/cat.js", "script", ResourceLoadPriorityMedium, WebURLRequest::RequestContextScript, true, "*/*"},
+        {"data://example.test/cat.css", "style", ResourceLoadPriorityHigh, WebURLRequest::RequestContextStyle, true, "text/css,*/*;q=0.1"},
+        // TODO(yoav): It doesn't seem like the audio context is ever used. That should probably be fixed (or we can consolidate audio and video).
+        {"data://example.test/cat.wav", "audio", ResourceLoadPriorityLow, WebURLRequest::RequestContextVideo, true, ""},
+        {"data://example.test/cat.mp4", "video", ResourceLoadPriorityLow, WebURLRequest::RequestContextVideo, true, ""},
+        {"data://example.test/cat.vtt", "track", ResourceLoadPriorityLow, WebURLRequest::RequestContextTrack, true, ""},
+        {"data://example.test/cat.woff", "font", ResourceLoadPriorityMedium, WebURLRequest::RequestContextFont, true, ""},
+        // TODO(yoav): subresource should be *very* low priority (rather than low).
+        {"data://example.test/cat.empty", "", ResourceLoadPriorityLow, WebURLRequest::RequestContextSubresource, true, ""},
+        {"data://example.test/cat.blob", "blabla", ResourceLoadPriorityLow, WebURLRequest::RequestContextSubresource, true, ""},
+        {"bla://example.test/cat.gif", "image", ResourceLoadPriorityUnresolved, WebURLRequest::RequestContextImage, false, ""},
     };
 
     // Test the cases with a single header
@@ -111,8 +121,12 @@
                 ASSERT_EQ((unsigned)0, preloads->size());
             } else {
                 ASSERT_EQ((unsigned)1, preloads->size());
-                if (preloads->size() > 0)
-                    ASSERT_EQ(testCase.priority, preloads->begin().get()->get()->resourceRequest().priority());
+                if (preloads->size() > 0) {
+                    Resource* resource = preloads->begin().get()->get();
+                    ASSERT_EQ(testCase.priority, resource->resourceRequest().priority());
+                    ASSERT_EQ(testCase.context, resource->resourceRequest().requestContext());
+                    ASSERT_STREQ(testCase.accept, resource->accept().string().ascii().data());
+                }
             }
         }
     }
diff --git a/third_party/WebKit/Source/core/loader/TextTrackLoader.h b/third_party/WebKit/Source/core/loader/TextTrackLoader.h
index b301b35..1677f88 100644
--- a/third_party/WebKit/Source/core/loader/TextTrackLoader.h
+++ b/third_party/WebKit/Source/core/loader/TextTrackLoader.h
@@ -38,9 +38,9 @@
 class Document;
 class TextTrackLoader;
 
-class TextTrackLoaderClient : public ResourceOwner<RawResource> {
+class TextTrackLoaderClient {
 public:
-    ~TextTrackLoaderClient() override {}
+    virtual ~TextTrackLoaderClient() {}
 
     virtual void newCuesAvailable(TextTrackLoader*) = 0;
     virtual void cueLoadingCompleted(TextTrackLoader*, bool loadingFailed) = 0;
diff --git a/third_party/WebKit/Source/core/page/ChromeClient.cpp b/third_party/WebKit/Source/core/page/ChromeClient.cpp
index ac605312..89c71fea 100644
--- a/third_party/WebKit/Source/core/page/ChromeClient.cpp
+++ b/third_party/WebKit/Source/core/page/ChromeClient.cpp
@@ -167,9 +167,20 @@
         }
     }
 
+    if (m_lastToolTipPoint == result.hitTestLocation().point() && m_lastToolTipText == toolTip)
+        return;
+    m_lastToolTipPoint = result.hitTestLocation().point();
+    m_lastToolTipText = toolTip;
     setToolTip(toolTip, toolTipDirection);
 }
 
+void ChromeClient::clearToolTip()
+{
+    // Do not check m_lastToolTip* and do not update them intentionally.
+    // We don't want to show tooltips with same content after clearToolTip().
+    setToolTip(String(), LTR);
+}
+
 void ChromeClient::print(LocalFrame* frame)
 {
     // Defer loads in case the client method runs a new event loop that would
diff --git a/third_party/WebKit/Source/core/page/ChromeClient.h b/third_party/WebKit/Source/core/page/ChromeClient.h
index 431a1f0b..771528b7 100644
--- a/third_party/WebKit/Source/core/page/ChromeClient.h
+++ b/third_party/WebKit/Source/core/page/ChromeClient.h
@@ -22,6 +22,7 @@
 #ifndef ChromeClient_h
 #define ChromeClient_h
 
+#include "base/gtest_prod_util.h"
 #include "core/CoreExport.h"
 #include "core/dom/AXObjectCache.h"
 #include "core/frame/ConsoleTypes.h"
@@ -155,6 +156,7 @@
 
     void mouseDidMoveOverElement(const HitTestResult&);
     virtual void setToolTip(const String&, TextDirection) = 0;
+    void clearToolTip();
 
     void print(LocalFrame*);
 
@@ -270,6 +272,11 @@
 private:
     bool canOpenModalIfDuringPageDismissal(Frame* mainFrame, DialogType, const String& message);
     void setToolTip(const HitTestResult&);
+
+    LayoutPoint m_lastToolTipPoint;
+    String m_lastToolTipText;
+
+    FRIEND_TEST_ALL_PREFIXES(ChromeClientTest, SetToolTipFlood);
 };
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/core/page/ChromeClientTest.cpp b/third_party/WebKit/Source/core/page/ChromeClientTest.cpp
new file mode 100644
index 0000000..42099adf
--- /dev/null
+++ b/third_party/WebKit/Source/core/page/ChromeClientTest.cpp
@@ -0,0 +1,70 @@
+// 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.
+
+#include "config.h"
+#include "core/page/ChromeClient.h"
+
+#include "core/dom/Document.h"
+#include "core/layout/HitTestResult.h"
+#include "core/loader/EmptyClients.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace blink {
+
+namespace {
+
+class ChromeClientToolTipLogger : public EmptyChromeClient {
+public:
+    void setToolTip(const String& text, TextDirection) override
+    {
+        m_toolTipForLastSetToolTip = text;
+    }
+
+    String toolTipForLastSetToolTip() const { return m_toolTipForLastSetToolTip; }
+    void clearToolTipForLastSetToolTip() { m_toolTipForLastSetToolTip = String(); }
+
+private:
+    String m_toolTipForLastSetToolTip;
+};
+
+} // anonymous namespace
+
+class ChromeClientTest : public testing::Test {
+};
+
+TEST_F(ChromeClientTest, SetToolTipFlood)
+{
+    ChromeClientToolTipLogger logger;
+    ChromeClient* client = &logger;
+    HitTestResult result(HitTestRequest(HitTestRequest::Move), LayoutPoint(10, 20));
+    RefPtrWillBeRawPtr<Document> doc = Document::create();
+    RefPtrWillBeRawPtr<Element> element = HTMLElement::create(HTMLNames::divTag, *doc);
+    element->setAttribute(HTMLNames::titleAttr, "tooltip");
+    result.setInnerNode(element.get());
+
+    client->setToolTip(result);
+    EXPECT_EQ("tooltip", logger.toolTipForLastSetToolTip());
+
+    // seToolTip(HitTestResult) again in the same condition.
+    logger.clearToolTipForLastSetToolTip();
+    client->setToolTip(result);
+    // setToolTip(String,TextDirection) should not be called.
+    EXPECT_EQ(String(), logger.toolTipForLastSetToolTip());
+
+    // Cancel the tooltip, and setToolTip(HitTestResult) again.
+    client->clearToolTip();
+    logger.clearToolTipForLastSetToolTip();
+    client->setToolTip(result);
+    // setToolTip(String,TextDirection) should not be called.
+    EXPECT_EQ(String(), logger.toolTipForLastSetToolTip());
+
+    logger.clearToolTipForLastSetToolTip();
+    element->setAttribute(HTMLNames::titleAttr, "updated");
+    client->setToolTip(result);
+    // setToolTip(String,TextDirection) should be called because tooltip string
+    // is different from the last one.
+    EXPECT_EQ("updated", logger.toolTipForLastSetToolTip());
+}
+
+} // namespace blink
diff --git a/third_party/WebKit/Source/core/page/FocusController.cpp b/third_party/WebKit/Source/core/page/FocusController.cpp
index 4bde2a9..dc9b4ac 100644
--- a/third_party/WebKit/Source/core/page/FocusController.cpp
+++ b/third_party/WebKit/Source/core/page/FocusController.cpp
@@ -43,6 +43,7 @@
 #include "core/frame/FrameView.h"
 #include "core/frame/LocalDOMWindow.h"
 #include "core/frame/LocalFrame.h"
+#include "core/frame/RemoteFrame.h"
 #include "core/frame/Settings.h"
 #include "core/html/HTMLAreaElement.h"
 #include "core/html/HTMLImageElement.h"
@@ -690,8 +691,13 @@
 {
     switch (type) {
     case WebFocusTypeForward:
-    case WebFocusTypeBackward:
-        return advanceFocusInDocumentOrder(type, initialFocus, sourceCapabilities);
+    case WebFocusTypeBackward: {
+        // We should never hit this when a RemoteFrame is focused, since the key
+        // event that initiated focus advancement should've been routed to that
+        // frame's process from the beginning.
+        LocalFrame* startingFrame = toLocalFrame(focusedOrMainFrame());
+        return advanceFocusInDocumentOrder(startingFrame, nullptr, type, initialFocus, sourceCapabilities);
+    }
     case WebFocusTypeLeft:
     case WebFocusTypeRight:
     case WebFocusTypeUp:
@@ -704,17 +710,30 @@
     return false;
 }
 
-bool FocusController::advanceFocusInDocumentOrder(WebFocusType type, bool initialFocus, InputDeviceCapabilities* sourceCapabilities)
+bool FocusController::advanceFocusAcrossFrames(WebFocusType type, RemoteFrame* from, LocalFrame* to, InputDeviceCapabilities* sourceCapabilities)
 {
-    // FIXME: Focus advancement won't work with externally rendered frames until after
-    // inter-frame focus control is moved out of Blink.
-    if (!focusedOrMainFrame()->isLocalFrame())
-        return false;
-    LocalFrame* frame = toLocalFrame(focusedOrMainFrame());
+    // If we are shifting focus from a child frame to its parent, the
+    // child frame has no more focusable elements, and we should continue
+    // looking for focusable elements in the parent, starting from the <iframe>
+    // element of the child frame.
+    Node* startingNode = nullptr;
+    if (from->tree().parent() == to) {
+        ASSERT(from->owner()->isLocal());
+        startingNode = toHTMLFrameOwnerElement(from->owner());
+    }
+
+    return advanceFocusInDocumentOrder(to, startingNode, type, false, sourceCapabilities);
+}
+
+bool FocusController::advanceFocusInDocumentOrder(LocalFrame* frame, Node* startingNode, WebFocusType type, bool initialFocus, InputDeviceCapabilities* sourceCapabilities)
+{
     ASSERT(frame);
     Document* document = frame->document();
 
-    Node* currentNode = document->focusedElement();
+    Node* currentNode = startingNode;
+    if (!currentNode)
+        currentNode = document->focusedElement();
+
     // FIXME: Not quite correct when it comes to focus transitions leaving/entering the WebView itself
     bool caretBrowsing = frame->settings() && frame->settings()->caretBrowsingEnabled();
 
@@ -726,6 +745,14 @@
     RefPtrWillBeRawPtr<Element> element = findFocusableElementAcrossFocusScopes(type, FocusNavigationScope::focusNavigationScopeOf(currentNode ? *currentNode : *document), currentNode);
 
     if (!element) {
+        // If there's a RemoteFrame on the ancestor chain, we need to continue
+        // searching for focusable elements there.
+        if (frame->localFrameRoot() != frame->tree().top()) {
+            document->clearFocusedElement();
+            toRemoteFrame(frame->localFrameRoot()->tree().parent())->advanceFocus(type, frame->localFrameRoot());
+            return true;
+        }
+
         // We didn't find an element to focus, so we should try to pass focus to Chrome.
         if (!initialFocus && m_page->chromeClient().canTakeFocus(type)) {
             document->clearFocusedElement();
@@ -735,9 +762,7 @@
         }
 
         // Chrome doesn't want focus, so we should wrap focus.
-        if (!m_page->mainFrame()->isLocalFrame())
-            return false;
-        element = findFocusableElementRecursively(type, FocusNavigationScope::focusNavigationScopeOf(*m_page->deprecatedLocalMainFrame()->document()), nullptr);
+        element = findFocusableElementRecursively(type, FocusNavigationScope::focusNavigationScopeOf(*toLocalFrame(m_page->mainFrame())->document()), nullptr);
         element = findFocusableElementDescendingDownIntoFrameDocument(type, element.get());
 
         if (!element)
@@ -760,6 +785,14 @@
 
         document->clearFocusedElement();
         setFocusedFrame(owner->contentFrame());
+
+        // If contentFrame is remote, continue the search for focusable
+        // elements in that frame's process.
+        // clearFocusedElement() fires events that might detach the
+        // contentFrame, hence the need to null-check it again.
+        if (owner->contentFrame() && owner->contentFrame()->isRemoteFrame())
+            toRemoteFrame(owner->contentFrame())->advanceFocus(type, frame);
+
         return true;
     }
 
diff --git a/third_party/WebKit/Source/core/page/FocusController.h b/third_party/WebKit/Source/core/page/FocusController.h
index 40cf228..1bc31f4 100644
--- a/third_party/WebKit/Source/core/page/FocusController.h
+++ b/third_party/WebKit/Source/core/page/FocusController.h
@@ -46,6 +46,7 @@
 class LocalFrame;
 class Node;
 class Page;
+class RemoteFrame;
 
 class CORE_EXPORT FocusController final : public NoBaseWillBeGarbageCollectedFinalized<FocusController> {
     WTF_MAKE_NONCOPYABLE(FocusController); USING_FAST_MALLOC_WILL_BE_REMOVED(FocusController);
@@ -68,6 +69,7 @@
 
     bool setInitialFocus(WebFocusType);
     bool advanceFocus(WebFocusType type, InputDeviceCapabilities* sourceCapabilities = nullptr) { return advanceFocus(type, false, sourceCapabilities); }
+    bool advanceFocusAcrossFrames(WebFocusType, RemoteFrame* from, LocalFrame* to, InputDeviceCapabilities* sourceCapabilities = nullptr);
     Element* findFocusableElement(WebFocusType, Node&);
 
     bool setFocusedElement(Element*, PassRefPtrWillBeRawPtr<Frame>, const FocusParams&);
@@ -88,7 +90,7 @@
 
     bool advanceFocus(WebFocusType, bool initialFocus, InputDeviceCapabilities* sourceCapabilities = nullptr);
     bool advanceFocusDirectionally(WebFocusType);
-    bool advanceFocusInDocumentOrder(WebFocusType, bool initialFocus, InputDeviceCapabilities* sourceCapabilities);
+    bool advanceFocusInDocumentOrder(LocalFrame*, Node* startingNode, WebFocusType, bool initialFocus, InputDeviceCapabilities* sourceCapabilities);
 
     bool advanceFocusDirectionallyInContainer(Node* container, const LayoutRect& startingRect, WebFocusType);
     void findFocusCandidateInContainer(Node& container, const LayoutRect& startingRect, WebFocusType, FocusCandidate& closest);
diff --git a/third_party/WebKit/Source/core/page/NetworkStateNotifier.cpp b/third_party/WebKit/Source/core/page/NetworkStateNotifier.cpp
index 6a5f39d..6f94f09 100644
--- a/third_party/WebKit/Source/core/page/NetworkStateNotifier.cpp
+++ b/third_party/WebKit/Source/core/page/NetworkStateNotifier.cpp
@@ -128,6 +128,8 @@
     ASSERT(isMainThread());
 
     MutexLocker locker(m_mutex);
+    m_initialized = true;
+
     if (m_type == type && m_maxBandwidthMbps == maxBandwidthMbps)
         return;
     m_type = type;
diff --git a/third_party/WebKit/Source/core/page/NetworkStateNotifier.h b/third_party/WebKit/Source/core/page/NetworkStateNotifier.h
index 5c372760..1514ba5d 100644
--- a/third_party/WebKit/Source/core/page/NetworkStateNotifier.h
+++ b/third_party/WebKit/Source/core/page/NetworkStateNotifier.h
@@ -47,9 +47,10 @@
     };
 
     NetworkStateNotifier()
-        : m_isOnLine(true)
+        : m_initialized(false)
+        , m_isOnLine(true)
         , m_type(WebConnectionTypeOther)
-        , m_maxBandwidthMbps(std::numeric_limits<double>::infinity())
+        , m_maxBandwidthMbps(kInvalidMaxBandwidth)
         , m_testUpdatesOnly(false)
     {
     }
@@ -58,6 +59,7 @@
     bool onLine() const
     {
         MutexLocker locker(m_mutex);
+        ASSERT(m_initialized);
         return m_isOnLine;
     }
 
@@ -67,6 +69,7 @@
     WebConnectionType connectionType() const
     {
         MutexLocker locker(m_mutex);
+        ASSERT(m_initialized);
         return m_type;
     }
 
@@ -74,6 +77,7 @@
     double maxBandwidth() const
     {
         MutexLocker locker(m_mutex);
+        ASSERT(m_initialized);
         return m_maxBandwidthMbps;
     }
 
@@ -109,6 +113,8 @@
         Vector<size_t> zeroedObservers; // Indices in observers that are 0.
     };
 
+    const int kInvalidMaxBandwidth = -1;
+
     void setWebConnectionImpl(WebConnectionType, double maxBandwidthMbps);
     void setMaxBandwidthImpl(double maxBandwidthMbps);
 
@@ -127,6 +133,7 @@
     void collectZeroedObservers(ObserverList*, ExecutionContext*);
 
     mutable Mutex m_mutex;
+    bool m_initialized;
     bool m_isOnLine;
     WebConnectionType m_type;
     double m_maxBandwidthMbps;
diff --git a/third_party/WebKit/Source/core/page/Page.cpp b/third_party/WebKit/Source/core/page/Page.cpp
index 3ec85f1..d06a8e1 100644
--- a/third_party/WebKit/Source/core/page/Page.cpp
+++ b/third_party/WebKit/Source/core/page/Page.cpp
@@ -89,6 +89,12 @@
     }
 }
 
+void Page::onMemoryPressure()
+{
+    for (auto& page : ordinaryPages())
+        page->memoryPurgeController().purgeMemory();
+}
+
 float deviceScaleFactor(LocalFrame* frame)
 {
     if (!frame)
@@ -361,13 +367,6 @@
         return;
     m_visibilityState = visibilityState;
 
-    if (visibilityState == PageVisibilityStateVisible) {
-        memoryPurgeController().pageBecameActive();
-    } else {
-        if (!isInitialState)
-            memoryPurgeController().pageBecameInactive();
-    }
-
     if (!isInitialState)
         notifyPageVisibilityChanged();
 
@@ -510,16 +509,14 @@
         frames[i]->localDOMWindow()->acceptLanguagesChanged();
 }
 
-void Page::purgeMemory(MemoryPurgeMode mode, DeviceKind deviceKind)
+void Page::purgeMemory(DeviceKind deviceKind)
 {
     Frame* frame = mainFrame();
     if (deviceKind != DeviceKind::LowEnd || !frame || !frame->isLocalFrame())
         return;
-    if (mode == MemoryPurgeMode::InactiveTab) {
-        if (Document* document = toLocalFrame(frame)->document())
-            document->fetcher()->garbageCollectDocumentResources();
-        memoryCache()->pruneAll();
-    }
+    if (Document* document = toLocalFrame(frame)->document())
+        document->fetcher()->garbageCollectDocumentResources();
+    memoryCache()->pruneAll();
 }
 
 DEFINE_TRACE(Page)
@@ -546,10 +543,16 @@
     MemoryPurgeClient::trace(visitor);
 }
 
-void Page::willCloseLayerTreeView()
+void Page::layerTreeViewInitialized(WebLayerTreeView& layerTreeView)
+{
+    if (scrollingCoordinator())
+        scrollingCoordinator()->layerTreeViewInitialized(layerTreeView);
+}
+
+void Page::willCloseLayerTreeView(WebLayerTreeView& layerTreeView)
 {
     if (m_scrollingCoordinator)
-        m_scrollingCoordinator->willCloseLayerTreeView();
+        m_scrollingCoordinator->willCloseLayerTreeView(layerTreeView);
 }
 
 void Page::willBeDestroyed()
diff --git a/third_party/WebKit/Source/core/page/Page.h b/third_party/WebKit/Source/core/page/Page.h
index 1ce3024..9389eb8 100644
--- a/third_party/WebKit/Source/core/page/Page.h
+++ b/third_party/WebKit/Source/core/page/Page.h
@@ -64,6 +64,7 @@
 class SpellCheckerClient;
 class UndoStack;
 class ValidationMessageClient;
+class WebLayerTreeView;
 
 typedef uint64_t LinkHash;
 
@@ -76,6 +77,7 @@
     friend class Settings;
 public:
     static void platformColorsChanged();
+    static void onMemoryPressure();
 
     // It is up to the platform to ensure that non-null clients are provided where required.
     struct CORE_EXPORT PageClients final {
@@ -201,11 +203,13 @@
 
     MemoryPurgeController& memoryPurgeController();
 
-    void purgeMemory(MemoryPurgeMode, DeviceKind) override;
+    void purgeMemory(DeviceKind) override;
 
     DECLARE_TRACE();
 
-    void willCloseLayerTreeView();
+    void layerTreeViewInitialized(WebLayerTreeView&);
+    void willCloseLayerTreeView(WebLayerTreeView&);
+
     void willBeDestroyed();
 
 private:
diff --git a/third_party/WebKit/Source/core/page/SpellCheckerClient.h b/third_party/WebKit/Source/core/page/SpellCheckerClient.h
index a3eff445..024e7bc0 100644
--- a/third_party/WebKit/Source/core/page/SpellCheckerClient.h
+++ b/third_party/WebKit/Source/core/page/SpellCheckerClient.h
@@ -39,7 +39,6 @@
 
     virtual bool isContinuousSpellCheckingEnabled() = 0;
     virtual void toggleContinuousSpellChecking() = 0;
-    virtual bool isGrammarCheckingEnabled() = 0;
 
     virtual TextCheckerClient& textChecker() = 0;
 
diff --git a/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator.cpp b/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator.cpp
index 21d9172..e7e5e58 100644
--- a/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator.cpp
+++ b/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator.cpp
@@ -59,6 +59,7 @@
 #include "public/platform/WebCompositorAnimationTimeline.h"
 #include "public/platform/WebCompositorSupport.h"
 #include "public/platform/WebLayerPositionConstraint.h"
+#include "public/platform/WebLayerTreeView.h"
 #include "public/platform/WebScrollbarLayer.h"
 #include "public/platform/WebScrollbarThemeGeometry.h"
 #include "public/platform/WebScrollbarThemePainter.h"
@@ -94,7 +95,6 @@
     , m_wasFrameScrollable(false)
     , m_lastMainThreadScrollingReasons(0)
 {
-    createProgrammaticScrollAnimatorTimeline();
 }
 
 ScrollingCoordinator::~ScrollingCoordinator()
@@ -720,17 +720,27 @@
     }
 }
 
-void ScrollingCoordinator::willCloseLayerTreeView()
+void ScrollingCoordinator::layerTreeViewInitialized(WebLayerTreeView& layerTreeView)
 {
-    destroyProgrammaticScrollAnimatorTimeline();
+    if (RuntimeEnabledFeatures::compositorAnimationTimelinesEnabled() && Platform::current()->isThreadedAnimationEnabled()) {
+        ASSERT(Platform::current()->compositorSupport());
+        m_programmaticScrollAnimatorTimeline = adoptPtr(Platform::current()->compositorSupport()->createAnimationTimeline());
+        layerTreeView.attachCompositorAnimationTimeline(m_programmaticScrollAnimatorTimeline.get());
+    }
+}
+
+void ScrollingCoordinator::willCloseLayerTreeView(WebLayerTreeView& layerTreeView)
+{
+    if (m_programmaticScrollAnimatorTimeline) {
+        layerTreeView.detachCompositorAnimationTimeline(m_programmaticScrollAnimatorTimeline.get());
+        m_programmaticScrollAnimatorTimeline.clear();
+    }
 }
 
 void ScrollingCoordinator::willBeDestroyed()
 {
     ASSERT(m_page);
 
-    destroyProgrammaticScrollAnimatorTimeline();
-
     m_page = nullptr;
     for (const auto& scrollbar : m_horizontalScrollbars)
         GraphicsLayer::unregisterContentsLayer(scrollbar.value->layer());
@@ -1075,26 +1085,4 @@
     return false;
 }
 
-void ScrollingCoordinator::createProgrammaticScrollAnimatorTimeline()
-{
-    if (RuntimeEnabledFeatures::compositorAnimationTimelinesEnabled() && Platform::current()->isThreadedAnimationEnabled()) {
-        ASSERT(m_page);
-        if (m_page->mainFrame()->isLocalFrame()) {
-            ASSERT(Platform::current()->compositorSupport());
-            m_programmaticScrollAnimatorTimeline = adoptPtr(Platform::current()->compositorSupport()->createAnimationTimeline());
-            m_page->chromeClient().attachCompositorAnimationTimeline(m_programmaticScrollAnimatorTimeline.get(), toLocalFrame(m_page->mainFrame()));
-        }
-    }
-}
-
-void ScrollingCoordinator::destroyProgrammaticScrollAnimatorTimeline()
-{
-    if (m_programmaticScrollAnimatorTimeline) {
-        ASSERT(m_page);
-        ASSERT(m_page->mainFrame()->isLocalFrame());
-        m_page->chromeClient().detachCompositorAnimationTimeline(m_programmaticScrollAnimatorTimeline.get(), toLocalFrame(m_page->mainFrame()));
-        m_programmaticScrollAnimatorTimeline.clear();
-    }
-}
-
 } // namespace blink
diff --git a/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator.h b/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator.h
index 6e3921c4..d18201e 100644
--- a/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator.h
+++ b/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator.h
@@ -49,6 +49,7 @@
 class Region;
 class ScrollableArea;
 class WebCompositorAnimationTimeline;
+class WebLayerTreeView;
 
 class CORE_EXPORT ScrollingCoordinator final : public NoBaseWillBeGarbageCollectedFinalized<ScrollingCoordinator> {
     WTF_MAKE_NONCOPYABLE(ScrollingCoordinator);
@@ -59,7 +60,9 @@
     ~ScrollingCoordinator();
     DECLARE_TRACE();
 
-    void willCloseLayerTreeView();
+    void layerTreeViewInitialized(WebLayerTreeView&);
+    void willCloseLayerTreeView(WebLayerTreeView&);
+
     void willBeDestroyed();
 
     // Return whether this scrolling coordinator handles scrolling for the given frame view.
@@ -156,9 +159,6 @@
 
     bool frameViewIsDirty() const;
 
-    void createProgrammaticScrollAnimatorTimeline();
-    void destroyProgrammaticScrollAnimatorTimeline();
-
     OwnPtr<WebCompositorAnimationTimeline> m_programmaticScrollAnimatorTimeline;
 
     using ScrollbarMap = WillBeHeapHashMap<RawPtrWillBeMember<ScrollableArea>, OwnPtr<WebScrollbarLayer>>;
diff --git a/third_party/WebKit/Source/core/paint/PaintLayer.cpp b/third_party/WebKit/Source/core/paint/PaintLayer.cpp
index 71c6999..df78365 100644
--- a/third_party/WebKit/Source/core/paint/PaintLayer.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintLayer.cpp
@@ -1546,7 +1546,7 @@
     return insideLayer;
 }
 
-Node* PaintLayer::enclosingElement() const
+Node* PaintLayer::enclosingNode() const
 {
     for (LayoutObject* r = layoutObject(); r; r = r->parent()) {
         if (Node* e = r->node())
@@ -1912,7 +1912,7 @@
             return false;
         }
 
-        Node* e = enclosingElement();
+        Node* e = enclosingNode();
         // FIXME: should be a call to result.setNodeAndPosition. What we would really want to do here is to
         // return and look for the nearest non-anonymous ancestor, and ignore aunts and uncles on
         // our way. It's bad to look for it manually like we do here, and give up on setting a local
@@ -2555,7 +2555,7 @@
 
 namespace {
 
-FilterOperations computeFilterOperationsHandleReferenceFilters(const FilterOperations& filters, float effectiveZoom, Node* enclosingElement)
+FilterOperations computeFilterOperationsHandleReferenceFilters(const FilterOperations& filters, float effectiveZoom, Node* enclosingNode)
 {
     if (filters.hasReferenceFilter()) {
         for (size_t i = 0; i < filters.size(); ++i) {
@@ -2564,7 +2564,7 @@
                 continue;
             ReferenceFilterOperation& referenceOperation = toReferenceFilterOperation(*filterOperation);
             // FIXME: Cache the Filter if it didn't change.
-            RefPtrWillBeRawPtr<Filter> referenceFilter = ReferenceFilterBuilder::build(effectiveZoom, toElement(enclosingElement), nullptr, referenceOperation);
+            RefPtrWillBeRawPtr<Filter> referenceFilter = ReferenceFilterBuilder::build(effectiveZoom, toElement(enclosingNode), nullptr, referenceOperation);
             referenceOperation.setFilter(referenceFilter.release());
         }
     }
@@ -2576,12 +2576,12 @@
 
 FilterOperations PaintLayer::computeFilterOperations(const ComputedStyle& style) const
 {
-    return computeFilterOperationsHandleReferenceFilters(style.filter(), style.effectiveZoom(), enclosingElement());
+    return computeFilterOperationsHandleReferenceFilters(style.filter(), style.effectiveZoom(), enclosingNode());
 }
 
 FilterOperations PaintLayer::computeBackdropFilterOperations(const ComputedStyle& style) const
 {
-    return computeFilterOperationsHandleReferenceFilters(style.backdropFilter(), style.effectiveZoom(), enclosingElement());
+    return computeFilterOperationsHandleReferenceFilters(style.backdropFilter(), style.effectiveZoom(), enclosingNode());
 }
 
 void PaintLayer::updateOrRemoveFilterClients()
@@ -2615,7 +2615,7 @@
     filterInfo->setBuilder(FilterEffectBuilder::create());
 
     float zoom = layoutObject()->style() ? layoutObject()->style()->effectiveZoom() : 1.0f;
-    if (!filterInfo->builder()->build(toElement(enclosingElement()), computeFilterOperations(layoutObject()->styleRef()), zoom))
+    if (!filterInfo->builder()->build(toElement(enclosingNode()), computeFilterOperations(layoutObject()->styleRef()), zoom))
         filterInfo->setBuilder(nullptr);
 
     return filterInfo->builder();
diff --git a/third_party/WebKit/Source/core/paint/PaintLayer.h b/third_party/WebKit/Source/core/paint/PaintLayer.h
index ccb4577..b49b421e 100644
--- a/third_party/WebKit/Source/core/paint/PaintLayer.h
+++ b/third_party/WebKit/Source/core/paint/PaintLayer.h
@@ -440,7 +440,7 @@
 
     void updateFilters(const ComputedStyle* oldStyle, const ComputedStyle& newStyle);
 
-    Node* enclosingElement() const;
+    Node* enclosingNode() const;
 
     bool isInTopLayer() const;
 
diff --git a/third_party/WebKit/Source/core/plugins/PluginView.h b/third_party/WebKit/Source/core/plugins/PluginView.h
index 372d999..638ae68 100644
--- a/third_party/WebKit/Source/core/plugins/PluginView.h
+++ b/third_party/WebKit/Source/core/plugins/PluginView.h
@@ -53,8 +53,6 @@
 
     virtual void didReceiveResponse(const ResourceResponse&) { }
     virtual void didReceiveData(const char*, int) { }
-    virtual void didFinishLoading() { }
-    virtual void didFailLoading(const ResourceError&) { }
 
     virtual void layoutIfNeeded() { }
     virtual void invalidatePaintIfNeeded() { }
diff --git a/third_party/WebKit/Source/core/style/ComputedStyle.cpp b/third_party/WebKit/Source/core/style/ComputedStyle.cpp
index f82d8cb..aca10ca0 100644
--- a/third_party/WebKit/Source/core/style/ComputedStyle.cpp
+++ b/third_party/WebKit/Source/core/style/ComputedStyle.cpp
@@ -266,6 +266,10 @@
     // unique() styles are not cacheable.
     ASSERT(!other.noninherited_flags.unique);
 
+    // styles with non inherited properties that reference variables are not
+    // cacheable.
+    ASSERT(!other.noninherited_flags.variableReference);
+
     // The following flags are set during matching before we decide that we get a
     // match in the MatchedPropertiesCache which in turn calls this method. The
     // reason why we don't copy these flags is that they're already correctly set
diff --git a/third_party/WebKit/Source/core/style/ComputedStyle.h b/third_party/WebKit/Source/core/style/ComputedStyle.h
index 43ca7e6..da23091 100644
--- a/third_party/WebKit/Source/core/style/ComputedStyle.h
+++ b/third_party/WebKit/Source/core/style/ComputedStyle.h
@@ -271,6 +271,7 @@
         unsigned styleType : 6; // PseudoId
         unsigned pseudoBits : 8;
         unsigned explicitInheritance : 1; // Explicitly inherits a non-inherited property
+        unsigned variableReference : 1; // A non-inherited property references a variable.
         unsigned unique : 1; // Style can not be shared.
 
         unsigned emptyState : 1;
@@ -284,7 +285,7 @@
 
         mutable unsigned hasRemUnits : 1;
         // If you add more style bits here, you will also need to update ComputedStyle::copyNonInheritedFromCached()
-        // 63 bits
+        // 62 bits
     } noninherited_flags;
 
 // !END SYNC!
@@ -326,6 +327,7 @@
         noninherited_flags.styleType = NOPSEUDO;
         noninherited_flags.pseudoBits = 0;
         noninherited_flags.explicitInheritance = false;
+        noninherited_flags.variableReference = false;
         noninherited_flags.unique = false;
         noninherited_flags.emptyState = false;
         noninherited_flags.hasViewportUnits = false;
@@ -821,6 +823,8 @@
     // through their self-painting layers. So the layout code doesn't account for them.
     bool hasVisualOverflowingEffect() const { return boxShadow() || hasBorderImageOutsets() || hasOutline(); }
 
+    Containment contain() const { return static_cast<Containment>(rareNonInheritedData->m_contain); }
+
     EBoxSizing boxSizing() const { return m_box->boxSizing(); }
     EUserModify userModify() const { return static_cast<EUserModify>(rareInheritedData->userModify); }
     EUserDrag userDrag() const { return static_cast<EUserDrag>(rareNonInheritedData->userDrag); }
@@ -1304,6 +1308,7 @@
     void setBoxShadow(PassRefPtr<ShadowList>);
     void setBoxReflect(PassRefPtr<StyleReflection> reflect) { if (rareNonInheritedData->m_boxReflect != reflect) rareNonInheritedData.access()->m_boxReflect = reflect; }
     void setBoxSizing(EBoxSizing s) { SET_VAR(m_box, m_boxSizing, s); }
+    void setContain(Containment contain) { SET_VAR(rareNonInheritedData, m_contain, contain); }
     void setFlexGrow(float f) { SET_VAR(rareNonInheritedData.access()->m_flexibleBox, m_flexGrow, f); }
     void setFlexShrink(float f) { SET_VAR(rareNonInheritedData.access()->m_flexibleBox, m_flexShrink, f); }
     void setFlexBasis(const Length& length) { SET_VAR(rareNonInheritedData.access()->m_flexibleBox, m_flexBasis, length); }
@@ -1601,6 +1606,9 @@
     void setHasExplicitlyInheritedProperties() { noninherited_flags.explicitInheritance = true; }
     bool hasExplicitlyInheritedProperties() const { return noninherited_flags.explicitInheritance; }
 
+    void setHasVariableReferenceFromNonInheritedProperty() { noninherited_flags.variableReference = true; }
+    bool hasVariableReferenceFromNonInheritedProperty() const { return noninherited_flags.variableReference; }
+
     bool hasChildDependentFlags() const { return emptyState() || hasExplicitlyInheritedProperties(); }
     void copyChildDependentFlagsFrom(const ComputedStyle&);
 
@@ -1623,6 +1631,7 @@
     static ECaptionSide initialCaptionSide() { return CAPTOP; }
     static EClear initialClear() { return CNONE; }
     static LengthBox initialClip() { return LengthBox(); }
+    static Containment initialContain() { return ContainsNone; }
     static TextDirection initialDirection() { return LTR; }
     static WritingMode initialWritingMode() { return TopToBottomWritingMode; }
     static TextCombine initialTextCombine() { return TextCombineNone; }
diff --git a/third_party/WebKit/Source/core/style/ComputedStyleConstants.h b/third_party/WebKit/Source/core/style/ComputedStyleConstants.h
index 14d6831..e15b5cb2 100644
--- a/third_party/WebKit/Source/core/style/ComputedStyleConstants.h
+++ b/third_party/WebKit/Source/core/style/ComputedStyleConstants.h
@@ -485,6 +485,17 @@
 
 enum EIsolation { IsolationAuto, IsolationIsolate };
 
+static const size_t ContainmentBits = 3;
+enum Containment {
+    ContainsNone = 0x0,
+    ContainsLayout = 0x1,
+    ContainsStyle = 0x2,
+    ContainsPaint = 0x4,
+    ContainsStrict = ContainsLayout | ContainsStyle | ContainsPaint,
+};
+inline Containment operator| (Containment a, Containment b) { return Containment(int(a) | int(b)); }
+inline Containment& operator|= (Containment& a, Containment b) { return a = a | b; }
+
 enum ItemPosition {
     ItemPositionAuto,
     ItemPositionStretch,
diff --git a/third_party/WebKit/Source/core/style/StyleRareNonInheritedData.cpp b/third_party/WebKit/Source/core/style/StyleRareNonInheritedData.cpp
index 66e520e3..b432ac9 100644
--- a/third_party/WebKit/Source/core/style/StyleRareNonInheritedData.cpp
+++ b/third_party/WebKit/Source/core/style/StyleRareNonInheritedData.cpp
@@ -118,6 +118,7 @@
     , m_touchAction(ComputedStyle::initialTouchAction())
     , m_objectFit(ComputedStyle::initialObjectFit())
     , m_isolation(ComputedStyle::initialIsolation())
+    , m_contain(ComputedStyle::initialContain())
     , m_scrollBehavior(ComputedStyle::initialScrollBehavior())
     , m_scrollSnapType(ComputedStyle::initialScrollSnapType())
     , m_requiresAcceleratedCompositingForExternalReasons(false)
@@ -199,6 +200,7 @@
     , m_touchAction(o.m_touchAction)
     , m_objectFit(o.m_objectFit)
     , m_isolation(o.m_isolation)
+    , m_contain(o.m_contain)
     , m_scrollBehavior(o.m_scrollBehavior)
     , m_scrollSnapType(o.m_scrollSnapType)
     , m_requiresAcceleratedCompositingForExternalReasons(o.m_requiresAcceleratedCompositingForExternalReasons)
@@ -289,6 +291,7 @@
         && m_touchAction == o.m_touchAction
         && m_objectFit == o.m_objectFit
         && m_isolation == o.m_isolation
+        && m_contain == o.m_contain
         && m_scrollBehavior == o.m_scrollBehavior
         && m_scrollSnapType == o.m_scrollSnapType
         && m_requiresAcceleratedCompositingForExternalReasons == o.m_requiresAcceleratedCompositingForExternalReasons
diff --git a/third_party/WebKit/Source/core/style/StyleRareNonInheritedData.h b/third_party/WebKit/Source/core/style/StyleRareNonInheritedData.h
index afd5c17c..64b6d65 100644
--- a/third_party/WebKit/Source/core/style/StyleRareNonInheritedData.h
+++ b/third_party/WebKit/Source/core/style/StyleRareNonInheritedData.h
@@ -189,6 +189,8 @@
 
     unsigned m_isolation : 1; // Isolation
 
+    unsigned m_contain : 3; // Containment
+
     // ScrollBehavior. 'scroll-behavior' has 2 accepted values, but ScrollBehavior has a third
     // value (that can only be specified using CSSOM scroll APIs) so 2 bits are needed.
     unsigned m_scrollBehavior: 2;
diff --git a/third_party/WebKit/Source/devtools/devtools.gypi b/third_party/WebKit/Source/devtools/devtools.gypi
index a6e8a4de..0f513c1 100644
--- a/third_party/WebKit/Source/devtools/devtools.gypi
+++ b/third_party/WebKit/Source/devtools/devtools.gypi
@@ -176,11 +176,10 @@
             'front_end/bindings/BlackboxSupport.js',
             'front_end/bindings/BreakpointManager.js',
             'front_end/bindings/CompilerScriptMapping.js',
-            'front_end/bindings/ContentProviderBasedProjectDelegate.js',
+            'front_end/bindings/ContentProviderBasedProject.js',
             'front_end/bindings/CSSWorkspaceBinding.js',
             'front_end/bindings/DebuggerWorkspaceBinding.js',
             'front_end/bindings/DefaultScriptMapping.js',
-            'front_end/bindings/ContentScriptProjectDecorator.js',
             'front_end/bindings/FileSystemWorkspaceBinding.js',
             'front_end/bindings/FileUtils.js',
             'front_end/bindings/LiveLocation.js',
@@ -670,7 +669,9 @@
         ],
         'devtools_timeline_js_files': [
             'front_end/timeline/invalidationsTree.css',
+            'front_end/timeline/timelineFlamechartPopover.css',
             'front_end/timeline/timelinePanel.css',
+            'front_end/timeline/timelineStatusDialog.css',
             'front_end/timeline/CountersGraph.js',
             'front_end/timeline/LayerDetailsView.js',
             'front_end/timeline/LayerTreeModel.js',
diff --git a/third_party/WebKit/Source/devtools/front_end/bindings/BreakpointManager.js b/third_party/WebKit/Source/devtools/front_end/bindings/BreakpointManager.js
index 34547b3..7477b7433 100644
--- a/third_party/WebKit/Source/devtools/front_end/bindings/BreakpointManager.js
+++ b/third_party/WebKit/Source/devtools/front_end/bindings/BreakpointManager.js
@@ -163,7 +163,7 @@
     {
         var uiSourceCode = /** @type {!WebInspector.UISourceCode} */ (event.data);
         this._restoreBreakpoints(uiSourceCode);
-        if (uiSourceCode.contentType() === WebInspector.resourceTypes.Script || uiSourceCode.contentType() === WebInspector.resourceTypes.Document)
+        if (uiSourceCode.contentType().hasScripts())
             uiSourceCode.addEventListener(WebInspector.UISourceCode.Events.SourceMappingChanged, this._uiSourceCodeMappingChanged, this);
     },
 
diff --git a/third_party/WebKit/Source/devtools/front_end/bindings/CompilerScriptMapping.js b/third_party/WebKit/Source/devtools/front_end/bindings/CompilerScriptMapping.js
index 311fdce..cdf9faa 100644
--- a/third_party/WebKit/Source/devtools/front_end/bindings/CompilerScriptMapping.js
+++ b/third_party/WebKit/Source/devtools/front_end/bindings/CompilerScriptMapping.js
@@ -61,7 +61,7 @@
     this._stubUISourceCodes = new Map();
 
     this._stubProjectID = "compiler-script-project";
-    this._stubProjectDelegate = new WebInspector.ContentProviderBasedProjectDelegate(this._workspace, this._stubProjectID, WebInspector.projectTypes.Service);
+    this._stubProject = new WebInspector.ContentProviderBasedProject(this._workspace, this._stubProjectID, WebInspector.projectTypes.Service, "", "");
     debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.GlobalObjectCleared, this._debuggerReset, this);
 }
 
@@ -166,12 +166,11 @@
         var splitURL = WebInspector.ParsedURL.splitURLIntoPathComponents(url);
         var parentPath = splitURL.slice(1, -1).join("/");
         var name = splitURL.peekLast() || "";
-        var uiSourceCodePath = this._stubProjectDelegate.addContentProvider(parentPath, name, url, new WebInspector.StaticContentProvider(WebInspector.resourceTypes.Script, "\n\n\n\n\n// Please wait a bit.\n// Compiled script is not shown while source map is being loaded!", url));
-        var stubUISourceCode = /** @type {!WebInspector.UISourceCode} */ (this._workspace.uiSourceCode(this._stubProjectID, uiSourceCodePath));
+        var stubUISourceCode = this._stubProject.addContentProvider(parentPath, name, url, new WebInspector.StaticContentProvider(WebInspector.resourceTypes.Script, "\n\n\n\n\n// Please wait a bit.\n// Compiled script is not shown while source map is being loaded!", url));
         this._stubUISourceCodes.set(script.scriptId, stubUISourceCode);
 
         this._debuggerWorkspaceBinding.pushSourceMapping(script, this);
-        this._loadSourceMapForScript(script, this._sourceMapLoaded.bind(this, script, uiSourceCodePath));
+        this._loadSourceMapForScript(script, this._sourceMapLoaded.bind(this, script, stubUISourceCode.path()));
     },
 
     /**
@@ -182,7 +181,7 @@
     _sourceMapLoaded: function(script, uiSourceCodePath, sourceMap)
     {
         this._stubUISourceCodes.delete(script.scriptId);
-        this._stubProjectDelegate.removeFile(uiSourceCodePath);
+        this._stubProject.removeFile(uiSourceCodePath);
 
         if (!sourceMap) {
             this._debuggerWorkspaceBinding.updateLocations(script);
@@ -206,7 +205,7 @@
                 continue;
             this._sourceMapForURL.set(sourceURL, sourceMap);
             if (!this._networkMapping.hasMappingForURL(sourceURL) && !this._networkMapping.uiSourceCodeForURL(sourceURL, script.target())) {
-                var contentProvider = sourceMap.sourceContentProvider(sourceURL, WebInspector.resourceTypes.Script);
+                var contentProvider = sourceMap.sourceContentProvider(sourceURL, WebInspector.resourceTypes.SourceMapScript);
                 this._networkProject.addFileForURL(sourceURL, contentProvider, script.isContentScript());
             }
             var uiSourceCode = this._networkMapping.uiSourceCodeForURL(sourceURL, this._target);
diff --git a/third_party/WebKit/Source/devtools/front_end/bindings/ContentProviderBasedProjectDelegate.js b/third_party/WebKit/Source/devtools/front_end/bindings/ContentProviderBasedProject.js
similarity index 69%
rename from third_party/WebKit/Source/devtools/front_end/bindings/ContentProviderBasedProjectDelegate.js
rename to third_party/WebKit/Source/devtools/front_end/bindings/ContentProviderBasedProject.js
index 781783c1..3b144b8 100644
--- a/third_party/WebKit/Source/devtools/front_end/bindings/ContentProviderBasedProjectDelegate.js
+++ b/third_party/WebKit/Source/devtools/front_end/bindings/ContentProviderBasedProject.js
@@ -30,79 +30,31 @@
 
  /**
  * @constructor
- * @extends {WebInspector.Object}
- * @implements {WebInspector.ProjectDelegate}
+ * @extends {WebInspector.ProjectStore}
+ * @implements {WebInspector.Project}
  * @param {!WebInspector.Workspace} workspace
  * @param {string} id
  * @param {!WebInspector.projectTypes} type
+ * @param {string} url
+ * @param {string} displayName
  */
-WebInspector.ContentProviderBasedProjectDelegate = function(workspace, id, type)
+WebInspector.ContentProviderBasedProject = function(workspace, id, type, url, displayName)
 {
-    WebInspector.Object.call(this);
-    this._type = type;
+    WebInspector.ProjectStore.call(this, workspace, id, type, url, displayName);
     /** @type {!Object.<string, !WebInspector.ContentProvider>} */
     this._contentProviders = {};
-    this._workspace = workspace;
-    this._id = id;
-    this._project = workspace.addProject(id, this);
+    workspace.addProject(this);
 }
 
-WebInspector.ContentProviderBasedProjectDelegate.prototype = {
-    /**
-     * @return {!WebInspector.Project}
-     */
-    project: function()
-    {
-        return this._project;
-    },
-
+WebInspector.ContentProviderBasedProject.prototype = {
     /**
      * @override
-     * @return {string}
-     */
-    type: function()
-    {
-        return this._type;
-    },
-
-    /**
-     * @override
-     * @return {string}
-     */
-    displayName: function()
-    {
-        // Overridden by subclasses
-        return "";
-    },
-
-    /**
-     * @override
-     * @return {string}
-     */
-    url: function()
-    {
-        // Overridden by subclasses
-        return "";
-    },
-
-    /**
-     * @override
-     * @param {string} path
-     * @param {function(?Date, ?number)} callback
-     */
-    requestMetadata: function(path, callback)
-    {
-        callback(null, null);
-    },
-
-    /**
-     * @override
-     * @param {string} path
+     * @param {!WebInspector.UISourceCode} uiSourceCode
      * @param {function(?string)} callback
      */
-    requestFileContent: function(path, callback)
+    requestFileContent: function(uiSourceCode, callback)
     {
-        var contentProvider = this._contentProviders[path];
+        var contentProvider = this._contentProviders[uiSourceCode.path()];
         contentProvider.requestContent(callback);
 
         /**
@@ -127,11 +79,11 @@
 
     /**
      * @override
-     * @param {string} path
+     * @param {!WebInspector.UISourceCode} uiSourceCode
      * @param {string} newContent
      * @param {function(?string)} callback
      */
-    setFileContent: function(path, newContent, callback)
+    setFileContent: function(uiSourceCode, newContent, callback)
     {
         callback(null);
     },
@@ -147,23 +99,30 @@
 
     /**
      * @override
-     * @param {string} path
+     * @param {!WebInspector.UISourceCode} uiSourceCode
      * @param {string} newName
      * @param {function(boolean, string=, string=, !WebInspector.ResourceType=)} callback
      */
-    rename: function(path, newName, callback)
+    rename: function(uiSourceCode, newName, callback)
     {
+        var path = uiSourceCode.path();
         this.performRename(path, newName, innerCallback.bind(this));
 
         /**
          * @param {boolean} success
          * @param {string=} newName
-         * @this {WebInspector.ContentProviderBasedProjectDelegate}
+         * @this {WebInspector.ContentProviderBasedProject}
          */
         function innerCallback(success, newName)
         {
-            if (success)
-                this._updateName(path, /** @type {string} */ (newName));
+            if (success && newName) {
+                var copyOfPath = path.split("/");
+                copyOfPath[copyOfPath.length - 1] = newName;
+                var newPath = copyOfPath.join("/");
+                this._contentProviders[newPath] = this._contentProviders[path];
+                delete this._contentProviders[path];
+                this.renameUISourceCode(uiSourceCode, newName);
+            }
             callback(success, newName);
         }
     },
@@ -192,7 +151,7 @@
      * @param {string} path
      * @param {?string} name
      * @param {string} content
-     * @param {function(?string)} callback
+     * @param {function(?WebInspector.UISourceCode)} callback
      */
     createFile: function(path, name, content, callback)
     {
@@ -224,30 +183,16 @@
     },
 
     /**
-     * @param {string} path
-     * @param {string} newName
-     */
-    _updateName: function(path, newName)
-    {
-        var oldPath = path;
-        var copyOfPath = path.split("/");
-        copyOfPath[copyOfPath.length - 1] = newName;
-        var newPath = copyOfPath.join("/");
-        this._contentProviders[newPath] = this._contentProviders[oldPath];
-        delete this._contentProviders[oldPath];
-    },
-
-    /**
      * @override
-     * @param {string} path
+     * @param {!WebInspector.UISourceCode} uiSourceCode
      * @param {string} query
      * @param {boolean} caseSensitive
      * @param {boolean} isRegex
      * @param {function(!Array.<!WebInspector.ContentProvider.SearchMatch>)} callback
      */
-    searchInFileContent: function(path, query, caseSensitive, isRegex, callback)
+    searchInFileContent: function(uiSourceCode, query, caseSensitive, isRegex, callback)
     {
-        var contentProvider = this._contentProviders[path];
+        var contentProvider = this._contentProviders[uiSourceCode.path()];
         contentProvider.searchInContent(query, caseSensitive, isRegex, callback);
     },
 
@@ -278,7 +223,7 @@
         /**
          * @param {string} path
          * @param {function(boolean)} callback
-         * @this {WebInspector.ContentProviderBasedProjectDelegate}
+         * @this {WebInspector.ContentProviderBasedProject}
          */
         function searchInContent(path, callback)
         {
@@ -286,7 +231,7 @@
             searchNextQuery.call(this);
 
             /**
-             * @this {WebInspector.ContentProviderBasedProjectDelegate}
+             * @this {WebInspector.ContentProviderBasedProject}
              */
             function searchNextQuery()
             {
@@ -300,7 +245,7 @@
 
             /**
              * @param {!Array.<!WebInspector.ContentProvider.SearchMatch>} searchMatches
-             * @this {WebInspector.ContentProviderBasedProjectDelegate}
+             * @this {WebInspector.ContentProviderBasedProject}
              */
             function contentCallback(searchMatches)
             {
@@ -336,7 +281,7 @@
      */
     indexContent: function(progress)
     {
-        setTimeout(progress.done.bind(progress), 0);
+        setImmediate(progress.done.bind(progress));
     },
 
     /**
@@ -344,17 +289,15 @@
      * @param {string} name
      * @param {string} originURL
      * @param {!WebInspector.ContentProvider} contentProvider
-     * @return {string}
+     * @return {!WebInspector.UISourceCode}
      */
     addContentProvider: function(parentPath, name, originURL, contentProvider)
     {
         var path = parentPath ? parentPath + "/" + name : name;
         if (this._contentProviders[path])
-            this.dispatchEventToListeners(WebInspector.ProjectDelegate.Events.FileRemoved, path);
-        var fileDescriptor = new WebInspector.FileDescriptor(parentPath, name, originURL, contentProvider.contentType());
+            this.removeUISourceCode(path);
         this._contentProviders[path] = contentProvider;
-        this.dispatchEventToListeners(WebInspector.ProjectDelegate.Events.FileAdded, fileDescriptor);
-        return path;
+        return this.addUISourceCode(parentPath, name, originURL, contentProvider.contentType());
     },
 
     /**
@@ -363,23 +306,21 @@
     removeFile: function(path)
     {
         delete this._contentProviders[path];
-        this.dispatchEventToListeners(WebInspector.ProjectDelegate.Events.FileRemoved, path);
-    },
-
-    /**
-     * @return {!Object.<string, !WebInspector.ContentProvider>}
-     */
-    contentProviders: function()
-    {
-        return this._contentProviders;
+        this.removeUISourceCode(path);
     },
 
     reset: function()
     {
         this._contentProviders = {};
-        this._workspace.removeProject(this._id);
-        this._workspace.addProject(this._id, this);
+        this.removeProject();
+        this.workspace().addProject(this);
     },
 
-    __proto__: WebInspector.Object.prototype
+    dispose: function()
+    {
+        this._contentProviders = {};
+        this.removeProject();
+    },
+
+    __proto__: WebInspector.ProjectStore.prototype
 }
diff --git a/third_party/WebKit/Source/devtools/front_end/bindings/ContentScriptProjectDecorator.js b/third_party/WebKit/Source/devtools/front_end/bindings/ContentScriptProjectDecorator.js
deleted file mode 100644
index 41c37d2..0000000
--- a/third_party/WebKit/Source/devtools/front_end/bindings/ContentScriptProjectDecorator.js
+++ /dev/null
@@ -1,77 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-/**
- * @constructor
- */
-WebInspector.ContentScriptProjectDecorator = function()
-{
-    WebInspector.targetManager.addModelListener(WebInspector.RuntimeModel, WebInspector.RuntimeModel.Events.ExecutionContextCreated, this._onContextCreated, this);
-    WebInspector.workspace.addEventListener(WebInspector.Workspace.Events.ProjectAdded, this._onProjectAdded, this);
-}
-
-/**
- * @param {!WebInspector.Project} project
- * @param {!WebInspector.ExecutionContext} context
- */
-WebInspector.ContentScriptProjectDecorator._updateProjectWithExtensionName = function(project, context)
-{
-    if (project.url().startsWith(context.origin))
-        project.setDisplayName(context.name);
-}
-
-WebInspector.ContentScriptProjectDecorator.prototype = {
-    /**
-     * @param {!WebInspector.Event} event
-     */
-    _onContextCreated: function(event)
-    {
-        var context = /** @type {!WebInspector.ExecutionContext} */(event.data);
-        if (!context.origin || !context.name)
-            return;
-
-        var projects = WebInspector.workspace.projects();
-        projects = projects.filter(contentProjectWithName);
-
-        for (var i = 0; i < projects.length; ++i)
-            WebInspector.ContentScriptProjectDecorator._updateProjectWithExtensionName(projects[i], context);
-
-        /**
-         * @param {!WebInspector.Project} project
-         * @return {boolean}
-         */
-        function contentProjectWithName(project)
-        {
-           return !!project.url() && project.type() === WebInspector.projectTypes.ContentScripts;
-        }
-    },
-
-    /**
-     * @param {!WebInspector.Event} event
-     */
-    _onProjectAdded: function(event)
-    {
-        var project = /** @type {!WebInspector.Project} */(event.data);
-        if (project.type() !== WebInspector.projectTypes.ContentScripts)
-            return;
-
-        var targets = WebInspector.targetManager.targets();
-        var contexts = [];
-        for (var i = 0; i < targets.length; ++i)
-            contexts = contexts.concat(targets[i].runtimeModel.executionContexts());
-        contexts = contexts.filter(contextWithOriginAndName);
-
-        for (var i = 0; i < contexts.length; ++i)
-            WebInspector.ContentScriptProjectDecorator._updateProjectWithExtensionName(project, contexts[i]);
-
-        /**
-         * @param {!WebInspector.ExecutionContext} context
-         * @return {boolean}
-         */
-        function contextWithOriginAndName(context)
-        {
-            return !!context.origin && !!context.name;
-        }
-    }
-}
\ No newline at end of file
diff --git a/third_party/WebKit/Source/devtools/front_end/bindings/DefaultScriptMapping.js b/third_party/WebKit/Source/devtools/front_end/bindings/DefaultScriptMapping.js
index 46d0872c..21030162 100644
--- a/third_party/WebKit/Source/devtools/front_end/bindings/DefaultScriptMapping.js
+++ b/third_party/WebKit/Source/devtools/front_end/bindings/DefaultScriptMapping.js
@@ -41,7 +41,7 @@
     this._debuggerWorkspaceBinding = debuggerWorkspaceBinding;
     this._workspace = workspace;
     this._projectId = WebInspector.DefaultScriptMapping.projectIdForTarget(debuggerModel.target());
-    this._projectDelegate = new WebInspector.DebuggerProjectDelegate(this._workspace, this._projectId, WebInspector.projectTypes.Debugger);
+    this._project = new WebInspector.ContentProviderBasedProject(this._workspace, this._projectId, WebInspector.projectTypes.Debugger, "debugger:", "");
     debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.GlobalObjectCleared, this._debuggerReset, this);
     this._debuggerReset();
 }
@@ -85,8 +85,12 @@
      */
     addScript: function(script)
     {
-        var path = this._projectDelegate.addScript(script);
-        var uiSourceCode = this._workspace.uiSourceCode(this._projectId, path);
+
+        var splitURL = WebInspector.ParsedURL.splitURLIntoPathComponents(script.sourceURL);
+        var name = splitURL[splitURL.length - 1];
+        name = "VM" + script.scriptId + (name ? " " + name : "");
+
+        var uiSourceCode = this._project.addContentProvider("", name, script.sourceURL, script);
         console.assert(uiSourceCode);
         uiSourceCode = /** @type {!WebInspector.UISourceCode} */ (uiSourceCode);
 
@@ -121,12 +125,12 @@
         /** @type {!Map.<string, !WebInspector.UISourceCode>} */
         this._uiSourceCodeForScriptId = new Map();
         this._scriptIdForUISourceCode = new Map();
-        this._projectDelegate.reset();
+        this._project.reset();
     },
 
     dispose: function()
     {
-        this._workspace.removeProject(this._projectId);
+        this._project.dispose();
     }
 }
 
@@ -138,49 +142,3 @@
 {
     return "debugger:" + target.id();
 }
-
-/**
- * @constructor
- * @param {!WebInspector.Workspace} workspace
- * @param {string} id
- * @param {!WebInspector.projectTypes} type
- * @extends {WebInspector.ContentProviderBasedProjectDelegate}
- */
-WebInspector.DebuggerProjectDelegate = function(workspace, id, type)
-{
-    WebInspector.ContentProviderBasedProjectDelegate.call(this, workspace, id, type);
-}
-
-WebInspector.DebuggerProjectDelegate.prototype = {
-    /**
-     * @override
-     * @return {string}
-     */
-    displayName: function()
-    {
-        return "";
-    },
-
-    /**
-     * @override
-     * @return {string}
-     */
-    url: function()
-    {
-        return "debugger:";
-    },
-
-    /**
-     * @param {!WebInspector.Script} script
-     * @return {string}
-     */
-    addScript: function(script)
-    {
-        var splitURL = WebInspector.ParsedURL.splitURLIntoPathComponents(script.sourceURL);
-        var name = splitURL[splitURL.length - 1];
-        name = "VM" + script.scriptId + (name ? " " + name : "");
-        return this.addContentProvider("", name, script.sourceURL, script);
-    },
-
-    __proto__: WebInspector.ContentProviderBasedProjectDelegate.prototype
-}
diff --git a/third_party/WebKit/Source/devtools/front_end/bindings/FileSystemWorkspaceBinding.js b/third_party/WebKit/Source/devtools/front_end/bindings/FileSystemWorkspaceBinding.js
index d8e69f0e..5d40a65b 100644
--- a/third_party/WebKit/Source/devtools/front_end/bindings/FileSystemWorkspaceBinding.js
+++ b/third_party/WebKit/Source/devtools/front_end/bindings/FileSystemWorkspaceBinding.js
@@ -233,38 +233,33 @@
 
 /**
  * @constructor
- * @extends {WebInspector.Object}
- * @implements {WebInspector.ProjectDelegate}
+ * @extends {WebInspector.ProjectStore}
+ * @implements {WebInspector.Project}
  * @param {!WebInspector.FileSystemWorkspaceBinding} fileSystemWorkspaceBinding
  * @param {!WebInspector.IsolatedFileSystem} isolatedFileSystem
  * @param {!WebInspector.Workspace} workspace
  */
 WebInspector.FileSystemWorkspaceBinding.FileSystem = function(fileSystemWorkspaceBinding, isolatedFileSystem, workspace)
 {
-    WebInspector.Object.call(this);
     this._fileSystemWorkspaceBinding = fileSystemWorkspaceBinding;
     this._fileSystem = isolatedFileSystem;
     this._fileSystemBaseURL = "file://" + this._fileSystem.normalizedPath() + "/";
-    this._fileSystemProjectURL = "filesystem:" + this._fileSystem.normalizedPath();
-    this._workspace = workspace;
 
-    this._projectId = WebInspector.FileSystemWorkspaceBinding.projectId(this._fileSystem.path());
-    console.assert(!this._workspace.project(this._projectId));
-    this._project = this._workspace.addProject(this._projectId, this);
+    var id = WebInspector.FileSystemWorkspaceBinding.projectId(this._fileSystem.path());
+    console.assert(!workspace.project(id));
+
+    var url = "filesystem:" + this._fileSystem.normalizedPath();
+    var normalizedPath = isolatedFileSystem.normalizedPath();
+    var displayName = normalizedPath.substr(normalizedPath.lastIndexOf("/") + 1);
+
+    WebInspector.ProjectStore.call(this, workspace, id, WebInspector.projectTypes.FileSystem, url, displayName);
+
+    workspace.addProject(this);
     this.populate();
 }
 
 WebInspector.FileSystemWorkspaceBinding.FileSystem.prototype = {
     /**
-     * @override
-     * @return {string}
-     */
-    type: function()
-    {
-        return WebInspector.projectTypes.FileSystem;
-    },
-
-    /**
      * @return {string}
      */
     fileSystemPath: function()
@@ -273,57 +268,27 @@
     },
 
     /**
-     * @override
+     * @param {!WebInspector.UISourceCode} uiSourceCode
      * @return {string}
      */
-    displayName: function()
+    _filePathForUISourceCode: function(uiSourceCode)
     {
-        var normalizedPath = this._fileSystem.normalizedPath();
-        return normalizedPath.substr(normalizedPath.lastIndexOf("/") + 1);
+        return "/" + uiSourceCode.path();
     },
 
     /**
      * @override
-     * @return {string}
-     */
-    url: function()
-    {
-        return this._fileSystemProjectURL;
-    },
-
-    /**
-     * @param {string} path
-     * @return {string}
-     */
-    _filePathForPath: function(path)
-    {
-        return "/" + path;
-    },
-
-    /**
-     * @override
-     * @param {string} path
+     * @param {!WebInspector.UISourceCode} uiSourceCode
      * @param {function(?string)} callback
      */
-    requestFileContent: function(path, callback)
+    requestFileContent: function(uiSourceCode, callback)
     {
-        var filePath = this._filePathForPath(path);
+        var filePath = this._filePathForUISourceCode(uiSourceCode);
         this._fileSystem.requestFileContent(filePath, callback);
     },
 
     /**
      * @override
-     * @param {string} path
-     * @param {function(?Date, ?number)} callback
-     */
-    requestMetadata: function(path, callback)
-    {
-        var filePath = this._filePathForPath(path);
-        this._fileSystem.requestMetadata(filePath, callback);
-    },
-
-    /**
-     * @override
      * @return {boolean}
      */
     canSetFileContent: function()
@@ -333,13 +298,13 @@
 
     /**
      * @override
-     * @param {string} path
+     * @param {!WebInspector.UISourceCode} uiSourceCode
      * @param {string} newContent
      * @param {function(?string)} callback
      */
-    setFileContent: function(path, newContent, callback)
+    setFileContent: function(uiSourceCode, newContent, callback)
     {
-        var filePath = this._filePathForPath(path);
+        var filePath = this._filePathForUISourceCode(uiSourceCode);
         this._fileSystem.setFileContent(filePath, newContent, callback.bind(this, ""));
     },
 
@@ -354,13 +319,18 @@
 
     /**
      * @override
-     * @param {string} path
+     * @param {!WebInspector.UISourceCode} uiSourceCode
      * @param {string} newName
      * @param {function(boolean, string=, string=, !WebInspector.ResourceType=)} callback
      */
-    rename: function(path, newName, callback)
+    rename: function(uiSourceCode, newName, callback)
     {
-        var filePath = this._filePathForPath(path);
+        if (newName === uiSourceCode.name()) {
+            callback(true, uiSourceCode.name(), uiSourceCode.originURL(), uiSourceCode.contentType());
+            return;
+        }
+
+        var filePath = this._filePathForUISourceCode(uiSourceCode);
         this._fileSystem.renameFile(filePath, newName, innerCallback.bind(this));
 
         /**
@@ -370,34 +340,34 @@
          */
         function innerCallback(success, newName)
         {
-            if (!success) {
+            if (!success || !newName) {
                 callback(false, newName);
                 return;
             }
-            var validNewName = /** @type {string} */ (newName);
-            console.assert(validNewName);
+            console.assert(newName);
             var slash = filePath.lastIndexOf("/");
             var parentPath = filePath.substring(0, slash);
-            filePath = parentPath + "/" + validNewName;
+            filePath = parentPath + "/" + newName;
             filePath = filePath.substr(1);
-            var extension = this._extensionForPath(validNewName);
+            var extension = this._extensionForPath(newName);
             var newOriginURL = this._fileSystemBaseURL + filePath;
             var newContentType = this._contentTypeForExtension(extension);
-            callback(true, validNewName, newOriginURL, newContentType);
+            this.renameUISourceCode(uiSourceCode, newName);
+            callback(true, newName, newOriginURL, newContentType);
         }
     },
 
     /**
      * @override
-     * @param {string} path
+     * @param {!WebInspector.UISourceCode} uiSourceCode
      * @param {string} query
      * @param {boolean} caseSensitive
      * @param {boolean} isRegex
      * @param {function(!Array.<!WebInspector.ContentProvider.SearchMatch>)} callback
      */
-    searchInFileContent: function(path, query, caseSensitive, isRegex, callback)
+    searchInFileContent: function(uiSourceCode, query, caseSensitive, isRegex, callback)
     {
-        var filePath = this._filePathForPath(path);
+        var filePath = this._filePathForUISourceCode(uiSourceCode);
         this._fileSystem.requestFileContent(filePath, contentCallback);
 
         /**
@@ -547,6 +517,12 @@
     excludeFolder: function(path)
     {
         this._fileSystem.addExcludedFolder(path);
+        var uiSourceCodes = this.uiSourceCodes().slice();
+        for (var i = 0; i < uiSourceCodes.length; ++i) {
+            var uiSourceCode = uiSourceCodes[i];
+            if (uiSourceCode.path().startsWith(path.substr(1)))
+                this.removeUISourceCode(uiSourceCode.path());
+        }
     },
 
     /**
@@ -554,7 +530,7 @@
      * @param {string} path
      * @param {?string} name
      * @param {string} content
-     * @param {function(?string)} callback
+     * @param {function(?WebInspector.UISourceCode)} callback
      */
     createFile: function(path, name, content, callback)
     {
@@ -584,8 +560,7 @@
          */
         function contentSet()
         {
-            this._addFile(createFilePath);
-            callback(createFilePath);
+            callback(this._addFile(createFilePath));
         }
     },
 
@@ -596,7 +571,7 @@
     deleteFile: function(path)
     {
         this._fileSystem.deleteFile(path);
-        this._removeFile(path);
+        this.removeUISourceCode(path);
     },
 
     /**
@@ -609,6 +584,7 @@
 
     /**
      * @param {string} filePath
+     * @return {!WebInspector.UISourceCode}
      */
     _addFile: function(filePath)
     {
@@ -622,16 +598,7 @@
         var extension = this._extensionForPath(name);
         var contentType = this._contentTypeForExtension(extension);
 
-        var fileDescriptor = new WebInspector.FileDescriptor(parentPath, name, this._fileSystemBaseURL + filePath, contentType);
-        this.dispatchEventToListeners(WebInspector.ProjectDelegate.Events.FileAdded, fileDescriptor);
-    },
-
-    /**
-     * @param {string} path
-     */
-    _removeFile: function(path)
-    {
-        this.dispatchEventToListeners(WebInspector.ProjectDelegate.Events.FileRemoved, path);
+        return this.addUISourceCode(parentPath, name, this._fileSystemBaseURL + filePath, contentType);
     },
 
     /**
@@ -639,18 +606,18 @@
      */
     _fileChanged: function(path)
     {
-        var uiSourceCode = this._project.uiSourceCode(path);
+        var uiSourceCode = this.uiSourceCode(path);
         if (!uiSourceCode) {
             this._addFile(path);
             return;
         }
-        this.dispatchEventToListeners(WebInspector.ProjectDelegate.Events.FileChanged, path);
+        uiSourceCode.checkContentUpdated();
     },
 
     dispose: function()
     {
-        this._workspace.removeProject(this._projectId);
+        this.removeProject();
     },
 
-    __proto__: WebInspector.Object.prototype
+    __proto__: WebInspector.ProjectStore.prototype
 }
diff --git a/third_party/WebKit/Source/devtools/front_end/bindings/NetworkProject.js b/third_party/WebKit/Source/devtools/front_end/bindings/NetworkProject.js
index c4b43b3..b1ac3f00 100644
--- a/third_party/WebKit/Source/devtools/front_end/bindings/NetworkProject.js
+++ b/third_party/WebKit/Source/devtools/front_end/bindings/NetworkProject.js
@@ -30,7 +30,7 @@
 
 /**
  * @constructor
- * @extends {WebInspector.ContentProviderBasedProjectDelegate}
+ * @extends {WebInspector.ContentProviderBasedProject}
  * @param {!WebInspector.Target} target
  * @param {!WebInspector.Workspace} workspace
  * @param {string} projectId
@@ -39,11 +39,8 @@
  */
 WebInspector.NetworkProjectDelegate = function(target, workspace, projectId, projectURL, projectType)
 {
-    this._url = projectURL;
     this._target = target;
-    this._id = projectId;
-    WebInspector.ContentProviderBasedProjectDelegate.call(this, workspace, projectId, projectType);
-    this.project()[WebInspector.NetworkProject._targetSymbol] = target;
+    WebInspector.ContentProviderBasedProject.call(this, workspace, projectId, projectType, projectURL, this._computeDisplayName(projectURL));
 }
 
 WebInspector.NetworkProjectDelegate.prototype = {
@@ -56,40 +53,22 @@
     },
 
     /**
+     * @param {string} url
      * @return {string}
      */
-    id: function()
+    _computeDisplayName: function(url)
     {
-        return this._id;
-    },
-
-    /**
-     * @override
-     * @return {string}
-     */
-    displayName: function()
-    {
-        if (typeof this._displayName !== "undefined")
-            return this._displayName;
+        for (var context of this._target.runtimeModel.executionContexts()) {
+            if (context.origin && url.startsWith(context.origin))
+                return context.name;
+        }
 
         var targetSuffix = this._target.isPage() ? "" : " \u2014 " + this._target.name();
-        if (!this._url) {
-            this._displayName = WebInspector.UIString("(no domain)") + targetSuffix;
-            return this._displayName;
-        }
-        var parsedURL = new WebInspector.ParsedURL(this._url);
+        if (!url)
+            return WebInspector.UIString("(no domain)") + targetSuffix;
+        var parsedURL = new WebInspector.ParsedURL(url);
         var prettyURL = parsedURL.isValid ? parsedURL.host + (parsedURL.port ? (":" + parsedURL.port) : "") : "";
-        this._displayName = (prettyURL || this._url) + targetSuffix;
-        return this._displayName;
-    },
-
-    /**
-     * @override
-     * @return {string}
-     */
-    url: function()
-    {
-        return this._url;
+        return (prettyURL || url) + targetSuffix;
     },
 
     /**
@@ -97,14 +76,14 @@
      * @param {string} name
      * @param {string} url
      * @param {!WebInspector.ContentProvider} contentProvider
-     * @return {string}
+     * @return {!WebInspector.UISourceCode}
      */
     addFile: function(parentPath, name, url, contentProvider)
     {
         return this.addContentProvider(parentPath, name, url, contentProvider);
     },
 
-    __proto__: WebInspector.ContentProviderBasedProjectDelegate.prototype
+    __proto__: WebInspector.ContentProviderBasedProject.prototype
 }
 
 /**
@@ -173,7 +152,6 @@
 }
 
 WebInspector.NetworkProject._networkProjectSymbol = Symbol("networkProject");
-WebInspector.NetworkProject._targetSymbol = Symbol("target");
 WebInspector.NetworkProject._contentTypeSymbol = Symbol("networkContentType");
 
 /**
@@ -188,15 +166,6 @@
 }
 
 /**
- * @param {!WebInspector.Project} project
- * @return {?WebInspector.Target}
- */
-WebInspector.NetworkProject._targetForProject = function(project)
-{
-    return project[WebInspector.NetworkProject._targetSymbol];
-}
-
-/**
  * @param {!WebInspector.Target} target
  * @return {!WebInspector.NetworkProject}
  */
@@ -214,7 +183,7 @@
     if (uiSourceCode.project().type() !== WebInspector.projectTypes.ContentScripts && uiSourceCode.project().type() !==  WebInspector.projectTypes.Network)
         return null;
 
-    return WebInspector.NetworkProject._targetForProject(uiSourceCode.project());
+    return /** @type {!WebInspector.NetworkProjectDelegate} */(uiSourceCode.project())._target;
 }
 
 /**
@@ -257,9 +226,7 @@
         var parentPath = splitURL.slice(1, -1).join("/");
         var name = splitURL.peekLast() || "";
         var projectDelegate = this._projectDelegate(projectURL, isContentScript || false);
-        var path = projectDelegate.addFile(parentPath, name, url, contentProvider);
-        var uiSourceCode = /** @type {!WebInspector.UISourceCode} */ (this._workspace.uiSourceCode(projectDelegate.id(), path));
-        console.assert(uiSourceCode);
+        var uiSourceCode = projectDelegate.addFile(parentPath, name, url, contentProvider);
         return uiSourceCode;
     },
 
@@ -391,7 +358,7 @@
             return;
 
         var type = contentProvider.contentType();
-        if (type !== WebInspector.resourceTypes.Stylesheet && type !== WebInspector.resourceTypes.Document && type !== WebInspector.resourceTypes.Script)
+        if (!type.isDocumentOrScriptOrStyleSheet())
             return;
         var uiSourceCode = this.addFileForURL(url, contentProvider, isContentScript);
         uiSourceCode[WebInspector.NetworkProject._contentTypeSymbol] = type;
diff --git a/third_party/WebKit/Source/devtools/front_end/bindings/ResourceScriptMapping.js b/third_party/WebKit/Source/devtools/front_end/bindings/ResourceScriptMapping.js
index ab30fa6..5418b484 100644
--- a/third_party/WebKit/Source/devtools/front_end/bindings/ResourceScriptMapping.js
+++ b/third_party/WebKit/Source/devtools/front_end/bindings/ResourceScriptMapping.js
@@ -159,7 +159,7 @@
         var uiSourceCode = /** @type {!WebInspector.UISourceCode} */ (event.data);
         if (!this._networkMapping.networkURL(uiSourceCode))
             return;
-        if (uiSourceCode.project().isServiceProject())
+        if (uiSourceCode.isFromServiceProject())
             return;
 
         var scripts = this._scriptsForUISourceCode(uiSourceCode);
@@ -177,7 +177,7 @@
         var uiSourceCode = /** @type {!WebInspector.UISourceCode} */ (event.data);
         if (!this._networkMapping.networkURL(uiSourceCode))
             return;
-        if (uiSourceCode.project().isServiceProject())
+        if (uiSourceCode.isFromServiceProject())
             return;
 
         this._unbindUISourceCode(uiSourceCode);
@@ -303,7 +303,7 @@
     this._uiSourceCode = uiSourceCode;
     this._uiSourceCode.forceLoadOnCheckContent();
 
-    if (this._uiSourceCode.contentType() === WebInspector.resourceTypes.Script)
+    if (this._uiSourceCode.contentType().isScript())
         this._script = scripts[0];
 
     this._uiSourceCode.addEventListener(WebInspector.UISourceCode.Events.WorkingCopyChanged, this._workingCopyChanged, this);
diff --git a/third_party/WebKit/Source/devtools/front_end/bindings/SASSSourceMapping.js b/third_party/WebKit/Source/devtools/front_end/bindings/SASSSourceMapping.js
index f2f1d1f..b95e046c 100644
--- a/third_party/WebKit/Source/devtools/front_end/bindings/SASSSourceMapping.js
+++ b/third_party/WebKit/Source/devtools/front_end/bindings/SASSSourceMapping.js
@@ -156,7 +156,7 @@
             for (var i = 0; i < sources.length; ++i) {
                 var sassURL = sources[i];
                 if (!this._networkMapping.hasMappingForURL(sassURL)) {
-                    var contentProvider = sourceMap.sourceContentProvider(sassURL, WebInspector.resourceTypes.Stylesheet);
+                    var contentProvider = sourceMap.sourceContentProvider(sassURL, WebInspector.resourceTypes.SourceMapStyleSheet);
                     this._networkProject.addFileForURL(sassURL, contentProvider);
                 }
             }
diff --git a/third_party/WebKit/Source/devtools/front_end/bindings/module.json b/third_party/WebKit/Source/devtools/front_end/bindings/module.json
index 4f2b5be..78f5f67ef 100644
--- a/third_party/WebKit/Source/devtools/front_end/bindings/module.json
+++ b/third_party/WebKit/Source/devtools/front_end/bindings/module.json
@@ -9,7 +9,7 @@
         "CSSWorkspaceBinding.js",
         "DebuggerWorkspaceBinding.js",
         "BreakpointManager.js",
-        "ContentProviderBasedProjectDelegate.js",
+        "ContentProviderBasedProject.js",
         "DefaultScriptMapping.js",
         "FileSystemWorkspaceBinding.js",
         "FileUtils.js",
@@ -18,7 +18,6 @@
         "NetworkProject.js",
         "PresentationConsoleMessageHelper.js",
         "ResourceUtils.js",
-        "TempFile.js",
-        "ContentScriptProjectDecorator.js"
+        "TempFile.js"
     ]
 }
diff --git a/third_party/WebKit/Source/devtools/front_end/common/ResourceType.js b/third_party/WebKit/Source/devtools/front_end/common/ResourceType.js
index ce79fbb..dabb735 100644
--- a/third_party/WebKit/Source/devtools/front_end/common/ResourceType.js
+++ b/third_party/WebKit/Source/devtools/front_end/common/ResourceType.js
@@ -76,6 +76,54 @@
     },
 
     /**
+     * @return {boolean}
+     */
+    isScript: function()
+    {
+        return this._name === "script" || this._name === "sm-script";
+    },
+
+    /**
+     * @return {boolean}
+     */
+    hasScripts: function()
+    {
+        return this.isScript() || this.isDocument();
+    },
+
+    /**
+     * @return {boolean}
+     */
+    isStyleSheet: function()
+    {
+        return this._name === "stylesheet" || this._name === "sm-stylesheet";
+    },
+
+    /**
+     * @return {boolean}
+     */
+    isDocument: function()
+    {
+        return this._name === "document";
+    },
+
+    /**
+     * @return {boolean}
+     */
+    isDocumentOrScriptOrStyleSheet: function()
+    {
+        return this.isDocument() || this.isScript() || this.isStyleSheet();
+    },
+
+    /**
+     * @return {boolean}
+     */
+    isFromSourceMap: function()
+    {
+        return this._name.startsWith("sm-");
+    },
+
+    /**
      * @override
      * @return {string}
      */
@@ -89,11 +137,11 @@
      */
     canonicalMimeType: function()
     {
-        if (this === WebInspector.resourceTypes.Document)
+        if (this.isDocument())
             return "text/html";
-        if (this === WebInspector.resourceTypes.Script)
+        if (this.isScript())
             return "text/javascript";
-        if (this === WebInspector.resourceTypes.Stylesheet)
+        if (this.isStyleSheet())
             return "text/css";
         return "";
     }
@@ -138,7 +186,9 @@
     Document: new WebInspector.ResourceType("document", "Document", WebInspector.resourceCategories.Document, true),
     TextTrack: new WebInspector.ResourceType("texttrack", "TextTrack", WebInspector.resourceCategories.Other, true),
     WebSocket: new WebInspector.ResourceType("websocket", "WebSocket", WebInspector.resourceCategories.WebSocket, false),
-    Other: new WebInspector.ResourceType("other", "Other", WebInspector.resourceCategories.Other, false)
+    Other: new WebInspector.ResourceType("other", "Other", WebInspector.resourceCategories.Other, false),
+    SourceMapScript: new WebInspector.ResourceType("sm-script", "Script", WebInspector.resourceCategories.Script, false),
+    SourceMapStyleSheet: new WebInspector.ResourceType("sm-stylesheet", "Stylesheet", WebInspector.resourceCategories.Stylesheet, false),
 }
 
 /**
diff --git a/third_party/WebKit/Source/devtools/front_end/components/HandlerRegistry.js b/third_party/WebKit/Source/devtools/front_end/components/HandlerRegistry.js
index 8468ad0..2137414 100644
--- a/third_party/WebKit/Source/devtools/front_end/components/HandlerRegistry.js
+++ b/third_party/WebKit/Source/devtools/front_end/components/HandlerRegistry.js
@@ -122,10 +122,7 @@
         if (!contentProvider.contentURL())
             return;
 
-        var contentType = contentProvider.contentType();
-        if (contentType !== WebInspector.resourceTypes.Document &&
-            contentType !== WebInspector.resourceTypes.Stylesheet &&
-            contentType !== WebInspector.resourceTypes.Script)
+        if (!contentProvider.contentType().isDocumentOrScriptOrStyleSheet())
             return;
 
         /**
diff --git a/third_party/WebKit/Source/devtools/front_end/elements/elementsTreeOutline.css b/third_party/WebKit/Source/devtools/front_end/elements/elementsTreeOutline.css
index beb5cfd..f7f1d7d3 100644
--- a/third_party/WebKit/Source/devtools/front_end/elements/elementsTreeOutline.css
+++ b/third_party/WebKit/Source/devtools/front_end/elements/elementsTreeOutline.css
@@ -257,11 +257,29 @@
     }
 }
 
+@-webkit-keyframes dom-update-highlight-animation-dark {
+    from {
+        background-color: rgb(158, 54, 153);
+        color: white;
+    }
+    80% {
+        background-color: #333;
+        color: inherit;
+    }
+    to {
+        background-color: inherit;
+    }
+}
+
 .dom-update-highlight {
     -webkit-animation: dom-update-highlight-animation 1.4s 1 cubic-bezier(0, 0, 0.2, 1);
     border-radius: 2px;
 }
 
+:host-context(.-theme-with-dark-background) .dom-update-highlight {
+    -webkit-animation: dom-update-highlight-animation-dark 1.4s 1 cubic-bezier(0, 0, 0.2, 1);
+}
+
 .elements-disclosure.single-node li {
     padding-left: 2px;
 }
diff --git a/third_party/WebKit/Source/devtools/front_end/main/Main.js b/third_party/WebKit/Source/devtools/front_end/main/Main.js
index 218c2c7..74b420c 100644
--- a/third_party/WebKit/Source/devtools/front_end/main/Main.js
+++ b/third_party/WebKit/Source/devtools/front_end/main/Main.js
@@ -207,7 +207,6 @@
         WebInspector.extensionServer = new WebInspector.ExtensionServer();
 
         new WebInspector.OverlayController();
-        new WebInspector.ContentScriptProjectDecorator();
         new WebInspector.ExecutionContextSelector(WebInspector.targetManager, WebInspector.context);
 
         var autoselectPanel = WebInspector.UIString("auto");
diff --git a/third_party/WebKit/Source/devtools/front_end/main/Tests.js b/third_party/WebKit/Source/devtools/front_end/main/Tests.js
index 69c0d8b..75b9568 100644
--- a/third_party/WebKit/Source/devtools/front_end/main/Tests.js
+++ b/third_party/WebKit/Source/devtools/front_end/main/Tests.js
@@ -701,7 +701,7 @@
 
     function filterOutService(uiSourceCode)
     {
-        return !uiSourceCode.project().isServiceProject();
+        return !uiSourceCode.isFromServiceProject();
     }
 
     var uiSourceCodes = WebInspector.workspace.uiSourceCodes();
diff --git a/third_party/WebKit/Source/devtools/front_end/popover.css b/third_party/WebKit/Source/devtools/front_end/popover.css
index 8ff24965..ef0064c 100644
--- a/third_party/WebKit/Source/devtools/front_end/popover.css
+++ b/third_party/WebKit/Source/devtools/front_end/popover.css
@@ -37,6 +37,10 @@
     left: 0;
 }
 
+.-theme-with-dark-background .popover .arrow {
+    -webkit-filter: invert(80%);
+}
+
 .popover.top-left-arrow .arrow {
     /* The default is top-left, no styles needed. */
 }
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/SourceMap.js b/third_party/WebKit/Source/devtools/front_end/sdk/SourceMap.js
index 56aee44..03f6c5d4 100644
--- a/third_party/WebKit/Source/devtools/front_end/sdk/SourceMap.js
+++ b/third_party/WebKit/Source/devtools/front_end/sdk/SourceMap.js
@@ -63,10 +63,11 @@
  * Implements Source Map V3 model. See http://code.google.com/p/closure-compiler/wiki/SourceMaps
  * for format description.
  * @constructor
+ * @param {string} compiledURL
  * @param {string} sourceMappingURL
  * @param {!SourceMapV3} payload
  */
-WebInspector.SourceMap = function(sourceMappingURL, payload)
+WebInspector.SourceMap = function(compiledURL, sourceMappingURL, payload)
 {
     if (!WebInspector.SourceMap.prototype._base64Map) {
         const base64Digits = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
@@ -75,6 +76,7 @@
             WebInspector.SourceMap.prototype._base64Map[base64Digits.charAt(i)] = i;
     }
 
+    this._compiledURL = compiledURL;
     this._sourceMappingURL = sourceMappingURL;
     this._reverseMappingsBySourceURL = new Map();
     this._mappings = [];
@@ -119,7 +121,7 @@
         try {
             var payload = /** @type {!SourceMapV3} */ (JSON.parse(content));
             var baseURL = sourceMapURL.startsWith("data:") ? compiledURL : sourceMapURL;
-            callback(new WebInspector.SourceMap(baseURL, payload));
+            callback(new WebInspector.SourceMap(compiledURL, baseURL, payload));
         } catch(e) {
             console.error(e.message);
             WebInspector.console.error("Failed to parse SourceMap: " + sourceMapURL);
@@ -285,19 +287,19 @@
         var nameIndex = 0;
 
         var sources = [];
-        var originalToCanonicalURLMap = {};
+        var sourceRoot = map.sourceRoot || "";
+        if (sourceRoot && !sourceRoot.endsWith("/"))
+            sourceRoot += "/";
         for (var i = 0; i < map.sources.length; ++i) {
-            var originalSourceURL = map.sources[i];
-            var sourceRoot = map.sourceRoot || "";
-            if (sourceRoot && !sourceRoot.endsWith("/"))
-                sourceRoot += "/";
-            var href = sourceRoot + originalSourceURL;
+            var href = sourceRoot + map.sources[i];
             var url = WebInspector.ParsedURL.completeURL(this._sourceMappingURL, href) || href;
-            originalToCanonicalURLMap[originalSourceURL] = url;
+            var hasSource = map.sourcesContent && map.sourcesContent[i];
+            if (url === this._compiledURL && hasSource)
+                url += WebInspector.UIString(" [sm]");
             sources.push(url);
             this._sources[url] = true;
 
-            if (map.sourcesContent && map.sourcesContent[i])
+            if (hasSource)
                 this._sourceContentByURL[url] = map.sourcesContent[i];
         }
 
diff --git a/third_party/WebKit/Source/devtools/front_end/snippets/ScriptSnippetModel.js b/third_party/WebKit/Source/devtools/front_end/snippets/ScriptSnippetModel.js
index 777730a..f2373200 100644
--- a/third_party/WebKit/Source/devtools/front_end/snippets/ScriptSnippetModel.js
+++ b/third_party/WebKit/Source/devtools/front_end/snippets/ScriptSnippetModel.js
@@ -46,9 +46,7 @@
     this._mappingForTarget = new Map();
     this._snippetStorage = new WebInspector.SnippetStorage("script", "Script snippet #");
     this._lastSnippetEvaluationIndexSetting = WebInspector.settings.createSetting("lastSnippetEvaluationIndex", 0);
-    this._projectId = WebInspector.projectTypes.Snippets + ":";
-    this._projectDelegate = new WebInspector.SnippetsProjectDelegate(workspace, this, this._projectId);
-    this._project = this._workspace.project(this._projectId);
+    this._project = new WebInspector.SnippetsProject(workspace, this);
     this._loadSnippets();
     WebInspector.targetManager.observeTargets(this);
 }
@@ -105,7 +103,7 @@
 
     /**
      * @param {string} content
-     * @return {string}
+     * @return {!WebInspector.UISourceCode}
      */
     createScriptSnippet: function(content)
     {
@@ -116,22 +114,17 @@
 
     /**
      * @param {!WebInspector.Snippet} snippet
-     * @return {string}
+     * @return {!WebInspector.UISourceCode}
      */
     _addScriptSnippet: function(snippet)
     {
-        var path = this._projectDelegate.addSnippet(snippet.name, new WebInspector.SnippetContentProvider(snippet));
-        var uiSourceCode = this._workspace.uiSourceCode(this._projectId, path);
-        if (!uiSourceCode) {
-            console.assert(uiSourceCode);
-            return "";
-        }
+        var uiSourceCode = this._project.addSnippet(snippet.name, new WebInspector.SnippetContentProvider(snippet));
         uiSourceCode.addEventListener(WebInspector.UISourceCode.Events.WorkingCopyChanged, this._workingCopyChanged, this);
         this._snippetIdForUISourceCode.set(uiSourceCode, snippet.id);
         var breakpointLocations = this._removeBreakpoints(uiSourceCode);
         this._restoreBreakpoints(uiSourceCode, breakpointLocations);
         this._uiSourceCodeForSnippetId[snippet.id] = uiSourceCode;
-        return path;
+        return uiSourceCode;
     },
 
     /**
@@ -148,7 +141,7 @@
      */
     deleteScriptSnippet: function(path)
     {
-        var uiSourceCode = this._workspace.uiSourceCode(this._projectId, path);
+        var uiSourceCode = this._project.uiSourceCode(path);
         if (!uiSourceCode)
             return;
         var snippetId = this._snippetIdForUISourceCode.get(uiSourceCode) || "";
@@ -158,7 +151,7 @@
         this._releaseSnippetScript(uiSourceCode);
         delete this._uiSourceCodeForSnippetId[snippet.id];
         this._snippetIdForUISourceCode.remove(uiSourceCode);
-        this._projectDelegate.removeFile(snippet.name);
+        this._project.removeFile(snippet.name);
     },
 
     /**
@@ -591,22 +584,21 @@
 
 /**
  * @constructor
- * @extends {WebInspector.ContentProviderBasedProjectDelegate}
+ * @extends {WebInspector.ContentProviderBasedProject}
  * @param {!WebInspector.Workspace} workspace
  * @param {!WebInspector.ScriptSnippetModel} model
- * @param {string} id
  */
-WebInspector.SnippetsProjectDelegate = function(workspace, model, id)
+WebInspector.SnippetsProject = function(workspace, model)
 {
-    WebInspector.ContentProviderBasedProjectDelegate.call(this, workspace, id, WebInspector.projectTypes.Snippets);
+    WebInspector.ContentProviderBasedProject.call(this, workspace, "snippets:", WebInspector.projectTypes.Snippets, "", "");
     this._model = model;
 }
 
-WebInspector.SnippetsProjectDelegate.prototype = {
+WebInspector.SnippetsProject.prototype = {
     /**
      * @param {string} name
      * @param {!WebInspector.ContentProvider} contentProvider
-     * @return {string}
+     * @return {!WebInspector.UISourceCode}
      */
     addSnippet: function(name, contentProvider)
     {
@@ -624,13 +616,13 @@
 
     /**
      * @override
-     * @param {string} path
+     * @param {!WebInspector.UISourceCode} uiSourceCode
      * @param {string} newContent
      * @param {function(?string)} callback
      */
-    setFileContent: function(path, newContent, callback)
+    setFileContent: function(uiSourceCode, newContent, callback)
     {
-        this._model._setScriptSnippetContent(path, newContent);
+        this._model._setScriptSnippetContent(uiSourceCode.path(), newContent);
         callback("");
     },
 
@@ -659,12 +651,11 @@
      * @param {string} path
      * @param {?string} name
      * @param {string} content
-     * @param {function(?string)} callback
+     * @param {function(?WebInspector.UISourceCode)} callback
      */
     createFile: function(path, name, content, callback)
     {
-        var filePath = this._model.createScriptSnippet(content);
-        callback(filePath);
+        callback(this._model.createScriptSnippet(content));
     },
 
     /**
@@ -676,7 +667,7 @@
         this._model.deleteScriptSnippet(path);
     },
 
-    __proto__: WebInspector.ContentProviderBasedProjectDelegate.prototype
+    __proto__: WebInspector.ContentProviderBasedProject.prototype
 }
 
 /**
diff --git a/third_party/WebKit/Source/devtools/front_end/source_frame/cmdevtools.css b/third_party/WebKit/Source/devtools/front_end/source_frame/cmdevtools.css
index 1ca0dd42..9e9e504 100644
--- a/third_party/WebKit/Source/devtools/front_end/source_frame/cmdevtools.css
+++ b/third_party/WebKit/Source/devtools/front_end/source_frame/cmdevtools.css
@@ -234,6 +234,14 @@
     z-index: -1;
 }
 
+.-theme-with-dark-background .cm-line-with-selection .cm-column-with-selection.cm-search-highlight:before {
+    background-color: hsl(133, 100%, 30%);
+}
+
+.-theme-with-dark-background.cm-line-with-selection .cm-search-highlight {
+    color: #333;
+}
+
 .CodeMirror .text-editor-line-decoration {
     position: absolute;
 }
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/FilteredItemSelectionDialog.js b/third_party/WebKit/Source/devtools/front_end/sources/FilteredItemSelectionDialog.js
index 46ab0833..b72a865 100644
--- a/third_party/WebKit/Source/devtools/front_end/sources/FilteredItemSelectionDialog.js
+++ b/third_party/WebKit/Source/devtools/front_end/sources/FilteredItemSelectionDialog.js
@@ -846,7 +846,7 @@
      */
     filterProject: function(project)
     {
-        return !project.isServiceProject();
+        return !WebInspector.Project.isServiceProject(project);
     },
 
     __proto__: WebInspector.SelectUISourceCodeDialog.prototype
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/InplaceFormatterEditorAction.js b/third_party/WebKit/Source/devtools/front_end/sources/InplaceFormatterEditorAction.js
index 86d28e5..baa0318 100644
--- a/third_party/WebKit/Source/devtools/front_end/sources/InplaceFormatterEditorAction.js
+++ b/third_party/WebKit/Source/devtools/front_end/sources/InplaceFormatterEditorAction.js
@@ -71,7 +71,7 @@
             return false;
         if (uiSourceCode.project().type() === WebInspector.projectTypes.FileSystem)
             return true;
-        return uiSourceCode.contentType() === WebInspector.resourceTypes.Stylesheet
+        return uiSourceCode.contentType().isStyleSheet()
             || uiSourceCode.project().type() === WebInspector.projectTypes.Snippets;
     },
 
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/JavaScriptSourceFrame.js b/third_party/WebKit/Source/devtools/front_end/sources/JavaScriptSourceFrame.js
index 8ed6c485..c53cd03 100644
--- a/third_party/WebKit/Source/devtools/front_end/sources/JavaScriptSourceFrame.js
+++ b/third_party/WebKit/Source/devtools/front_end/sources/JavaScriptSourceFrame.js
@@ -88,7 +88,7 @@
 
     _showDivergedInfobar: function()
     {
-        if (this._uiSourceCode.contentType() !== WebInspector.resourceTypes.Script)
+        if (!this._uiSourceCode.contentType().isScript())
             return;
 
         if (this._divergedInfobar)
@@ -127,8 +127,7 @@
 
     _showBlackboxInfobarIfNeeded: function()
     {
-        var contentType = this._uiSourceCode.contentType();
-        if (contentType !== WebInspector.resourceTypes.Script && contentType !== WebInspector.resourceTypes.Document)
+        if (!this._uiSourceCode.contentType().hasScripts())
             return;
         var projectType = this._uiSourceCode.project().type();
         if (projectType === WebInspector.projectTypes.Snippets)
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/NavigatorView.js b/third_party/WebKit/Source/devtools/front_end/sources/NavigatorView.js
index 6b13bcf5..da8f97c24 100644
--- a/third_party/WebKit/Source/devtools/front_end/sources/NavigatorView.js
+++ b/third_party/WebKit/Source/devtools/front_end/sources/NavigatorView.js
@@ -65,7 +65,8 @@
     Domain: "Domain",
     Folder: "Folder",
     UISourceCode: "UISourceCode",
-    FileSystem: "FileSystem"
+    FileSystem: "FileSystem",
+    SourceMapFolder: "SourceMapFolder"
 }
 
 /**
@@ -78,6 +79,8 @@
         return "navigator-domain-tree-item";
     if (type === WebInspector.NavigatorView.Types.FileSystem)
         return "navigator-folder-tree-item";
+    if (type === WebInspector.NavigatorView.Types.SourceMapFolder)
+        return "navigator-sm-folder-tree-item";
     return "navigator-folder-tree-item";
 }
 
@@ -118,7 +121,7 @@
      */
     accept: function(uiSourceCode)
     {
-        return !uiSourceCode.project().isServiceProject();
+        return !uiSourceCode.isFromServiceProject();
     },
 
     /**
@@ -128,8 +131,9 @@
     {
         if (!this.accept(uiSourceCode))
             return;
-        var projectNode = this._projectNode(uiSourceCode.project());
-        var folderNode = this._folderNode(projectNode, uiSourceCode.parentPath());
+        var isFromSourceMap = uiSourceCode.contentType().isFromSourceMap();
+        var projectNode = this._projectNode(uiSourceCode.project(), isFromSourceMap);
+        var folderNode = this._folderNode(projectNode, uiSourceCode.parentPath(), isFromSourceMap);
         var uiSourceCodeNode = new WebInspector.NavigatorUISourceCodeTreeNode(this, uiSourceCode);
         this._uiSourceCodeNodes.set(uiSourceCode, uiSourceCodeNode);
         folderNode.appendChild(uiSourceCodeNode);
@@ -159,7 +163,6 @@
     _projectRemoved: function(event)
     {
         var project = /** @type {!WebInspector.Project} */ (event.data);
-        project.removeEventListener(WebInspector.Project.Events.DisplayNameUpdated, this._updateProjectNodeTitle, this);
         var uiSourceCodes = project.uiSourceCodes();
         for (var i = 0; i < uiSourceCodes.length; ++i)
             this._removeUISourceCode(uiSourceCodes[i]);
@@ -167,16 +170,17 @@
 
     /**
      * @param {!WebInspector.Project} project
+     * @param {boolean} isFromSourceMap
      * @return {!WebInspector.NavigatorTreeNode}
      */
-    _projectNode: function(project)
+    _projectNode: function(project, isFromSourceMap)
     {
         if (!project.displayName())
             return this._rootNode;
 
         var projectNode = this._rootNode.child(project.id());
         if (!projectNode) {
-            projectNode = this._createProjectNode(project);
+            projectNode = this._createProjectNode(project, isFromSourceMap);
             this._rootNode.appendChild(projectNode);
         }
         return projectNode;
@@ -184,34 +188,27 @@
 
     /**
      * @param {!WebInspector.Project} project
+     * @param {boolean} isFromSourceMap
      * @return {!WebInspector.NavigatorTreeNode}
      */
-    _createProjectNode: function(project)
+    _createProjectNode: function(project, isFromSourceMap)
     {
-        var type = project.type() === WebInspector.projectTypes.FileSystem ? WebInspector.NavigatorView.Types.FileSystem : WebInspector.NavigatorView.Types.Domain;
+        var type;
+        if (isFromSourceMap)
+            type = WebInspector.NavigatorView.Types.SourceMapFolder;
+        else
+            type = project.type() === WebInspector.projectTypes.FileSystem ? WebInspector.NavigatorView.Types.FileSystem : WebInspector.NavigatorView.Types.Domain;
         var projectNode = new WebInspector.NavigatorFolderTreeNode(this, project, project.id(), type, "", project.displayName());
-        project.addEventListener(WebInspector.Project.Events.DisplayNameUpdated, this._updateProjectNodeTitle, this);
         return projectNode;
     },
 
     /**
-     * @param {!WebInspector.Event} event
-     */
-    _updateProjectNodeTitle: function(event)
-    {
-        var project = /** @type {!WebInspector.Project} */(event.target);
-        var projectNode = this._rootNode.child(project.id());
-        if (!projectNode)
-            return;
-        projectNode.treeNode().titleText = project.displayName();
-    },
-
-    /**
-     * @param {!WebInspector.NavigatorTreeNode} projectNode
+    * @param {!WebInspector.NavigatorTreeNode} projectNode
      * @param {string} folderPath
+     * @param {boolean} fromSourceMap
      * @return {!WebInspector.NavigatorTreeNode}
      */
-    _folderNode: function(projectNode, folderPath)
+    _folderNode: function(projectNode, folderPath, fromSourceMap)
     {
         if (!folderPath)
             return projectNode;
@@ -229,10 +226,10 @@
         var parentNode = projectNode;
         var index = folderPath.lastIndexOf("/");
         if (index !== -1)
-            parentNode = this._folderNode(projectNode, folderPath.substring(0, index));
+            parentNode = this._folderNode(projectNode, folderPath.substring(0, index), fromSourceMap);
 
         var name = folderPath.substring(index + 1);
-        folderNode = new WebInspector.NavigatorFolderTreeNode(this, null, name, WebInspector.NavigatorView.Types.Folder, folderPath, name);
+        folderNode = new WebInspector.NavigatorFolderTreeNode(this, null, name, fromSourceMap ? WebInspector.NavigatorView.Types.SourceMapFolder : WebInspector.NavigatorView.Types.Folder, folderPath, name);
         subfolderNodes.set(folderPath, folderNode);
         parentNode.appendChild(folderNode);
         return folderNode;
@@ -280,7 +277,7 @@
         if (!node)
             return;
 
-        var projectNode = this._projectNode(uiSourceCode.project());
+        var projectNode = this._projectNode(uiSourceCode.project(), false);
         var subfolderNodes = this._subfolderNodes.get(projectNode);
         var parentNode = node.parent;
         this._uiSourceCodeNodes.remove(uiSourceCode);
@@ -504,18 +501,12 @@
 
         /**
          * @this {WebInspector.NavigatorView}
-         * @param {?string} path
+         * @param {?WebInspector.UISourceCode} uiSourceCode
          */
-        function fileCreated(path)
+        function fileCreated(uiSourceCode)
         {
-            if (!path)
+            if (!uiSourceCode)
                 return;
-            filePath = path;
-            uiSourceCode = project.uiSourceCode(filePath);
-            if (!uiSourceCode) {
-                console.assert(uiSourceCode);
-                return;
-            }
             this._sourceSelected(uiSourceCode, false);
             this.revealUISourceCode(uiSourceCode, true);
             this.rename(uiSourceCode, true);
@@ -615,13 +606,13 @@
     {
         var type = treeElement.type();
         if (type === WebInspector.NavigatorView.Types.Domain) {
-            if (treeElement.titleText === WebInspector.targetManager.inspectedPageDomain())
+            if (treeElement.nodeTitle() === WebInspector.targetManager.inspectedPageDomain())
                 return 1;
             return 2;
         }
         if (type === WebInspector.NavigatorView.Types.FileSystem)
             return 3;
-        if (type === WebInspector.NavigatorView.Types.Folder)
+        if (type === WebInspector.NavigatorView.Types.Folder || type === WebInspector.NavigatorView.Types.SourceMapFolder)
             return 4;
         return 5;
     }
@@ -635,8 +626,8 @@
     else if (typeWeight1 < typeWeight2)
         result = -1;
     else {
-        var title1 = treeElement1.titleText;
-        var title2 = treeElement2.titleText;
+        var title1 = treeElement1.nodeTitle();
+        var title2 = treeElement2.nodeTitle();
         result = title1.compareTo(title2);
     }
     return result;
@@ -676,6 +667,7 @@
 
         this.titleElement = this.listItemElement.createChild("div", "base-navigator-tree-element-title");
         this.titleElement.textContent = this._titleText;
+        this.tooltip = this._tooltip || this._titleText;
     },
 
     /**
@@ -693,19 +685,24 @@
     /**
      * @return {string}
      */
-    get titleText()
+    nodeTitle: function()
     {
         return this._titleText;
     },
 
-    set titleText(titleText)
+    /**
+     * @param {string} titleText
+     * @param {string=} tooltip
+     */
+    setNodeTitle: function(titleText, tooltip)
     {
-        if (this._titleText === titleText)
+        if (this._titleText === titleText && this._tooltip === tooltip)
             return;
         this._titleText = titleText || "";
+        this._tooltip = tooltip;
         if (this.titleElement) {
             this.titleElement.textContent = this._titleText;
-            this.titleElement.title = this._titleText;
+            this.tooltip = this._tooltip || this._titleText;
         }
     },
 
@@ -1155,7 +1152,10 @@
         var titleText = this._uiSourceCode.displayName();
         if (!ignoreIsDirty && (this._uiSourceCode.isDirty() || this._uiSourceCode.hasUnsavedCommittedChanges()))
             titleText = "*" + titleText;
-        this._treeElement.titleText = titleText;
+        var tooltip = titleText;
+        if (this._uiSourceCode.contentType().isFromSourceMap())
+            tooltip = WebInspector.UIString("%s (from source map)", this._uiSourceCode.displayName());
+        this._treeElement.setNodeTitle(titleText, tooltip);
     },
 
     /**
@@ -1224,7 +1224,7 @@
         function commitHandler(element, newTitle, oldTitle)
         {
             if (newTitle !== oldTitle) {
-                this._treeElement.titleText = newTitle;
+                this._treeElement.setNodeTitle(newTitle);
                 this._uiSourceCode.rename(newTitle, renameCallback.bind(this));
                 return;
             }
@@ -1356,7 +1356,7 @@
 
         if (children.length === 1 && this._shouldMerge(node)) {
             node._isMerged = true;
-            this._treeElement.titleText = this._treeElement.titleText + "/" + node._title;
+            this._treeElement.setNodeTitle(this._treeElement.nodeTitle() + "/" + node._title);
             node._treeElement = this._treeElement;
             this._treeElement.setNode(node);
             return;
@@ -1386,7 +1386,7 @@
             } while (treeNode && treeNode._isMerged);
 
             if (!this.isPopulated()) {
-                this._treeElement.titleText = titleText;
+                this._treeElement.setNodeTitle(titleText);
                 this._treeElement.setNode(this);
                 for (var i = 0; i < nodes.length; ++i) {
                     delete nodes[i]._treeElement;
@@ -1401,7 +1401,7 @@
             oldTreeElement.parent.appendChild(treeElement);
 
             oldTreeElement.setNode(nodes[nodes.length - 1]);
-            oldTreeElement.titleText = nodes.map(titleForNode).join("/");
+            oldTreeElement.setNodeTitle(nodes.map(titleForNode).join("/"));
             oldTreeElement.parent.removeChild(oldTreeElement);
             this._treeElement.appendChild(oldTreeElement);
             if (oldTreeElement.expanded)
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/ScriptFormatter.js b/third_party/WebKit/Source/devtools/front_end/sources/ScriptFormatter.js
index 8e72d27c..b9314fc0 100644
--- a/third_party/WebKit/Source/devtools/front_end/sources/ScriptFormatter.js
+++ b/third_party/WebKit/Source/devtools/front_end/sources/ScriptFormatter.js
@@ -43,7 +43,7 @@
  */
 WebInspector.Formatter.format = function(contentType, mimeType, content, callback)
 {
-    if (contentType === WebInspector.resourceTypes.Script || contentType === WebInspector.resourceTypes.Document || contentType === WebInspector.resourceTypes.Stylesheet)
+    if (contentType.isDocumentOrScriptOrStyleSheet())
         new WebInspector.ScriptFormatter(mimeType, content, callback);
     else
         new WebInspector.IdentityFormatter(mimeType, content, callback);
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/ScriptFormatterEditorAction.js b/third_party/WebKit/Source/devtools/front_end/sources/ScriptFormatterEditorAction.js
index 5d4a951..62d8a16 100644
--- a/third_party/WebKit/Source/devtools/front_end/sources/ScriptFormatterEditorAction.js
+++ b/third_party/WebKit/Source/devtools/front_end/sources/ScriptFormatterEditorAction.js
@@ -97,58 +97,13 @@
 
 /**
  * @constructor
- * @param {!WebInspector.Workspace} workspace
- * @param {string} id
- * @extends {WebInspector.ContentProviderBasedProjectDelegate}
- */
-WebInspector.FormatterProjectDelegate = function(workspace, id)
-{
-    WebInspector.ContentProviderBasedProjectDelegate.call(this, workspace, id, WebInspector.projectTypes.Formatter);
-}
-
-WebInspector.FormatterProjectDelegate.prototype = {
-    /**
-     * @override
-     * @return {string}
-     */
-    displayName: function()
-    {
-        return "formatter";
-    },
-
-    /**
-     * @param {string} name
-     * @param {string} sourceURL
-     * @param {!WebInspector.ResourceType} contentType
-     * @param {string} content
-     * @return {string}
-     */
-    _addFormatted: function(name, sourceURL, contentType, content)
-    {
-        var contentProvider = new WebInspector.StaticContentProvider(contentType, content);
-        return this.addContentProvider(sourceURL, name + ":formatted", sourceURL, contentProvider);
-    },
-
-    /**
-     * @param {string} path
-     */
-    _removeFormatted: function(path)
-    {
-        this.removeFile(path);
-    },
-
-    __proto__: WebInspector.ContentProviderBasedProjectDelegate.prototype
-}
-
-/**
- * @constructor
  * @implements {WebInspector.SourcesView.EditorAction}
  * @implements {WebInspector.TargetManager.Observer}
  */
 WebInspector.ScriptFormatterEditorAction = function()
 {
     this._projectId = "formatter:";
-    this._projectDelegate = new WebInspector.FormatterProjectDelegate(WebInspector.workspace, this._projectId);
+    this._project = new WebInspector.ContentProviderBasedProject(WebInspector.workspace, this._projectId, WebInspector.projectTypes.Formatter, "", "formatter");
 
     /** @type {!Map.<!WebInspector.Script, !WebInspector.UISourceCode>} */
     this._uiSourceCodes = new Map();
@@ -262,8 +217,7 @@
         var supportedProjectTypes = [WebInspector.projectTypes.Network, WebInspector.projectTypes.Debugger, WebInspector.projectTypes.ContentScripts];
         if (supportedProjectTypes.indexOf(uiSourceCode.project().type()) === -1)
             return false;
-        var contentType = uiSourceCode.contentType();
-        return contentType === WebInspector.resourceTypes.Script || contentType === WebInspector.resourceTypes.Document;
+        return uiSourceCode.contentType().hasScripts();
     },
 
     _toggleFormatScriptSource: function()
@@ -311,7 +265,7 @@
             this._uiSourceCodes.remove(formatData.scripts[i]);
             WebInspector.debuggerWorkspaceBinding.popSourceMapping(formatData.scripts[i]);
         }
-        this._projectDelegate._removeFormatted(formattedUISourceCode.path());
+        this._project.removeFile(formattedUISourceCode.path());
     },
 
     /**
@@ -336,7 +290,7 @@
             else {
                 this._formattedPaths.remove(formatData.projectId + ":" + formatData.path);
                 this._formatData.remove(uiSourceCodes[i]);
-                this._projectDelegate._removeFormatted(uiSourceCodes[i].path());
+                this._project.removeFile(uiSourceCodes[i].path());
             }
         }
     },
@@ -374,7 +328,7 @@
             }
             return scripts.filter(isInlineScript);
         }
-        if (uiSourceCode.contentType() === WebInspector.resourceTypes.Script) {
+        if (uiSourceCode.contentType().isScript()) {
             var rawLocations = WebInspector.debuggerWorkspaceBinding.uiLocationToRawLocations(uiSourceCode, 0, 0);
             return rawLocations.map(function(rawLocation) { return rawLocation.script(); });
         }
@@ -423,8 +377,10 @@
                 name = uiSourceCode.name() || (scripts.length ? scripts[0].scriptId : "");
 
             var networkURL = WebInspector.networkMapping.networkURL(uiSourceCode);
-            formattedPath = this._projectDelegate._addFormatted(name, networkURL, uiSourceCode.contentType(), formattedContent);
-            var formattedUISourceCode = /** @type {!WebInspector.UISourceCode} */ (this._workspace.uiSourceCode(this._projectId, formattedPath));
+
+            var contentProvider = new WebInspector.StaticContentProvider(uiSourceCode.contentType(), formattedContent);
+            var formattedUISourceCode = this._project.addContentProvider(networkURL, name + ":formatted", networkURL, contentProvider);
+            var formattedPath = formattedUISourceCode.path();
             var formatData = new WebInspector.FormatterScriptMapping.FormatData(uiSourceCode.project().id(), uiSourceCode.path(), formatterMapping, scripts);
             this._formatData.set(formattedUISourceCode, formatData);
             var path = uiSourceCode.project().id() + ":" + uiSourceCode.path();
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/SourcesPanel.js b/third_party/WebKit/Source/devtools/front_end/sources/SourcesPanel.js
index 8bff5d3..e9b17c9 100644
--- a/third_party/WebKit/Source/devtools/front_end/sources/SourcesPanel.js
+++ b/third_party/WebKit/Source/devtools/front_end/sources/SourcesPanel.js
@@ -926,14 +926,14 @@
         var projectType = uiSourceCode.project().type();
 
         var contentType = uiSourceCode.contentType();
-        if (contentType === WebInspector.resourceTypes.Script || contentType === WebInspector.resourceTypes.Document) {
+        if (contentType.hasScripts()) {
             var target = WebInspector.context.flavor(WebInspector.Target);
             var debuggerModel = WebInspector.DebuggerModel.fromTarget(target);
             if (debuggerModel && debuggerModel.isPaused())
                 contextMenu.appendItem(WebInspector.UIString.capitalize("Continue to ^here"), this._continueToLocation.bind(this, uiLocation));
         }
 
-        if ((contentType === WebInspector.resourceTypes.Script || contentType === WebInspector.resourceTypes.Document) && projectType !== WebInspector.projectTypes.Snippets) {
+        if (contentType.hasScripts() && projectType !== WebInspector.projectTypes.Snippets) {
             var networkURL = this._networkMapping.networkURL(uiSourceCode);
             var url = projectType === WebInspector.projectTypes.Formatter ? uiSourceCode.originURL() : networkURL;
             this.sidebarPanes.callstack.appendBlackboxURLContextMenuItems(contextMenu, url, projectType === WebInspector.projectTypes.ContentScripts);
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/SourcesSearchScope.js b/third_party/WebKit/Source/devtools/front_end/sources/SourcesSearchScope.js
index 2520b99..e5798f0 100644
--- a/third_party/WebKit/Source/devtools/front_end/sources/SourcesSearchScope.js
+++ b/third_party/WebKit/Source/devtools/front_end/sources/SourcesSearchScope.js
@@ -86,7 +86,7 @@
          */
         function filterOutServiceProjects(project)
         {
-            return !project.isServiceProject() || project.type() === WebInspector.projectTypes.Formatter;
+            return !WebInspector.Project.isServiceProject(project) || project.type() === WebInspector.projectTypes.Formatter;
         }
 
         /**
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/SourcesView.js b/third_party/WebKit/Source/devtools/front_end/sources/SourcesView.js
index a406574b..04028e7 100644
--- a/third_party/WebKit/Source/devtools/front_end/sources/SourcesView.js
+++ b/third_party/WebKit/Source/devtools/front_end/sources/SourcesView.js
@@ -253,7 +253,7 @@
      */
     _addUISourceCode: function(uiSourceCode)
     {
-        if (uiSourceCode.project().isServiceProject())
+        if (uiSourceCode.isFromServiceProject())
             return;
         this._editorContainer.addUISourceCode(uiSourceCode);
         // Replace debugger script-based uiSourceCode with a network-based one.
@@ -262,7 +262,7 @@
             return;
         var networkURL = WebInspector.networkMapping.networkURL(uiSourceCode);
         var currentNetworkURL = WebInspector.networkMapping.networkURL(currentUISourceCode);
-        if (currentUISourceCode.project().isServiceProject() && currentUISourceCode !== uiSourceCode && currentNetworkURL === networkURL && networkURL) {
+        if (currentUISourceCode.isFromServiceProject() && currentUISourceCode !== uiSourceCode && currentNetworkURL === networkURL && networkURL) {
             this._showFile(uiSourceCode);
             this._editorContainer.removeUISourceCode(currentUISourceCode);
         }
@@ -345,20 +345,13 @@
     _createSourceFrame: function(uiSourceCode)
     {
         var sourceFrame;
-        switch (uiSourceCode.contentType()) {
-        case WebInspector.resourceTypes.Script:
+        var contentType = uiSourceCode.contentType();
+        if (contentType.hasScripts())
             sourceFrame = new WebInspector.JavaScriptSourceFrame(this._sourcesPanel, uiSourceCode);
-            break;
-        case WebInspector.resourceTypes.Document:
-            sourceFrame = new WebInspector.JavaScriptSourceFrame(this._sourcesPanel, uiSourceCode);
-            break;
-        case WebInspector.resourceTypes.Stylesheet:
+        else if (contentType.isStyleSheet())
             sourceFrame = new WebInspector.CSSSourceFrame(uiSourceCode);
-            break;
-        default:
+        else
             sourceFrame = new WebInspector.UISourceCodeFrame(uiSourceCode);
-        break;
-        }
         sourceFrame.setHighlighterType(WebInspector.SourcesView.uiSourceCodeHighlighterType(uiSourceCode));
         this._sourceFramesByUISourceCode.set(uiSourceCode, sourceFrame);
         this._historyManager.trackSourceFrameCursorJumps(sourceFrame);
@@ -381,15 +374,11 @@
      */
     _sourceFrameMatchesUISourceCode: function(sourceFrame, uiSourceCode)
     {
-        switch (uiSourceCode.contentType()) {
-        case WebInspector.resourceTypes.Script:
-        case WebInspector.resourceTypes.Document:
+        if (uiSourceCode.contentType().hasScripts())
             return sourceFrame instanceof WebInspector.JavaScriptSourceFrame;
-        case WebInspector.resourceTypes.Stylesheet:
+        if (uiSourceCode.contentType().isStyleSheet())
             return sourceFrame instanceof WebInspector.CSSSourceFrame;
-        default:
-            return !(sourceFrame instanceof WebInspector.JavaScriptSourceFrame);
-        }
+        return !(sourceFrame instanceof WebInspector.JavaScriptSourceFrame);
     },
 
     /**
@@ -646,18 +635,18 @@
         if (!uiSourceCode)
             return false;
 
-        switch (uiSourceCode.contentType()) {
-        case WebInspector.resourceTypes.Document:
-        case WebInspector.resourceTypes.Script:
+        if (uiSourceCode.contentType().hasScripts()) {
             WebInspector.JavaScriptOutlineDialog.show(uiSourceCode, this.showSourceLocation.bind(this, uiSourceCode));
             return true;
-        case WebInspector.resourceTypes.Stylesheet:
+        }
+
+        if (uiSourceCode.contentType().isStyleSheet()) {
             WebInspector.StyleSheetOutlineDialog.show(uiSourceCode, this.showSourceLocation.bind(this, uiSourceCode));
             return true;
-        default:
-            // We don't want default browser shortcut to be executed, so pretend to handle this event.
-            return true;
         }
+
+        // We don't want default browser shortcut to be executed, so pretend to handle this event.
+        return true;
     },
 
     /**
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/navigatorView.css b/third_party/WebKit/Source/devtools/front_end/sources/navigatorView.css
index 9dbb3c91..dc69a9ab7 100644
--- a/third_party/WebKit/Source/devtools/front_end/sources/navigatorView.css
+++ b/third_party/WebKit/Source/devtools/front_end/sources/navigatorView.css
@@ -31,19 +31,34 @@
     content: url(Images/domain.png);
 }
 
-.navigator-folder-tree-item .icon {
+.navigator-folder-tree-item .icon,
+.navigator-sm-folder-tree-item .icon {
     opacity: 0.7;
     content: url(Images/frame.png);
 }
 
-.navigator-script-tree-item .icon {
+.navigator-script-tree-item .icon,
+.navigator-sm-script-tree-item .icon {
     content: url(Images/resourceJSIcon.png);
 }
 
-.navigator-stylesheet-tree-item .icon {
+.navigator-stylesheet-tree-item .icon,
+.navigator-sm-stylesheet-tree-item .icon {
     content: url(Images/resourceCSSIcon.png);
 }
 
+.navigator-sm-folder-tree-item .icon,
+.navigator-sm-script-tree-item .icon,
+.navigator-sm-stylesheet-tree-item .icon {
+    -webkit-filter: saturate(0);
+}
+
+.navigator-sm-folder-tree-item .base-navigator-tree-element-title,
+.navigator-sm-script-tree-item .base-navigator-tree-element-title,
+.navigator-sm-stylesheet-tree-item .base-navigator-tree-element-title {
+    font-style: italic;
+}
+
 .navigator-document-tree-item .icon {
     content: url(Images/resourceDocumentIcon.png);
 }
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineFlameChart.js b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineFlameChart.js
index 7e0a4a5..46718f0 100644
--- a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineFlameChart.js
+++ b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineFlameChart.js
@@ -522,6 +522,49 @@
     /**
      * @override
      * @param {number} entryIndex
+     * @return {?Array.<!{title: string, value: (string|!Element)}>}
+     */
+    prepareHighlightedEntryInfo: function(entryIndex)
+    {
+        var event = this._entryEvents[entryIndex];
+        var time;
+        var title;
+        var warning;
+        if (event) {
+            var totalTime = event.duration;
+            var selfTime = event.selfTime;
+            var /** @const */ eps = 1e-6;
+            time = typeof totalTime === "number" && Math.abs(totalTime - selfTime) > eps && selfTime > eps ?
+                WebInspector.UIString("%s (self %s)", Number.millisToString(totalTime, true), Number.millisToString(selfTime, true)) :
+                Number.millisToString(totalTime, true);
+            title = this.entryTitle(entryIndex);
+            warning = WebInspector.TimelineUIUtils.eventWarning(event);
+        } else {
+            var frame = this._entryIndexToFrame[entryIndex];
+            if (!frame)
+                return null;
+            time = WebInspector.UIString("%s ~ %.0f\u2009fps", Number.preciseMillisToString(frame.duration, 1), (1000 / frame.duration));
+            title = frame.idle ? WebInspector.UIString("Idle Frame") : WebInspector.UIString("Frame");
+            if (frame.hasWarnings()) {
+                warning = createElement("span");
+                warning.textContent = WebInspector.UIString("Long frame");
+            }
+        }
+        var value = createElement("div");
+        var root = WebInspector.createShadowRootWithCoreStyles(value, "timeline/timelineFlamechartPopover.css");
+        var contents = root.createChild("div", "timeline-flamechart-popover");
+        contents.createChild("span", "timeline-info-time").textContent = time;
+        contents.createChild("span", "timeline-info-title").textContent = title;
+        if (warning) {
+            warning.classList.add("timeline-info-warning");
+            contents.appendChild(warning);
+        }
+        return [{ title: "", value: value }];
+    },
+
+    /**
+     * @override
+     * @param {number} entryIndex
      * @return {string}
      */
     entryColor: function(entryIndex)
@@ -959,15 +1002,17 @@
         if (!request.url)
             return null;
         var value = createElement("div");
+        var root = WebInspector.createShadowRootWithCoreStyles(value, "timeline/timelineFlamechartPopover.css");
+        var contents = root.createChild("div", "timeline-flamechart-popover");
         var duration = request.endTime - request.startTime;
         if (request.startTime && isFinite(duration))
-            value.createChild("span", "timeline-network-info-duration").textContent = Number.millisToString(duration);
+            contents.createChild("span", "timeline-info-network-time").textContent = Number.millisToString(duration);
         if (typeof request.priority === "string") {
-            var div = value.createChild("span", "timeline-network-info-priority");
+            var div = contents.createChild("span");
             div.textContent = WebInspector.uiLabelForPriority(/** @type {!NetworkAgent.ResourcePriority} */ (request.priority));
             div.style.color = this._colorForPriority(request.priority) || "black";
         }
-        value.createChild("span", "timeline-network-info-url").textContent = request.url.trimMiddle(maxURLChars);
+        contents.createChild("span").textContent = request.url.trimMiddle(maxURLChars);
         return [{ title: "", value: value }];
     },
 
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineUIUtils.js b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineUIUtils.js
index bb190fd..fd8ece2 100644
--- a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineUIUtils.js
+++ b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineUIUtils.js
@@ -591,7 +591,7 @@
     var contentHelper = new WebInspector.TimelineDetailsContentHelper(model.target(), linkifier, relatedNodesMap, true);
 
     if (event.warning)
-        contentHelper.appendWarningRow(event.warning, event);
+        contentHelper.appendWarningRow(event);
 
     if (detailed) {
         contentHelper.appendTextRow(WebInspector.UIString("Type"), WebInspector.TimelineUIUtils.eventTitle(event));
@@ -617,7 +617,7 @@
             contentHelper.appendElementRow(WebInspector.UIString("Function"), detailsNode);
         var deoptReason = eventData["deoptReason"];
         if (deoptReason && deoptReason != "no reason")
-            contentHelper.appendWarningRow(WebInspector.TimelineModel.WarningType.V8Deopt, event);
+            contentHelper.appendWarningRow(event, WebInspector.TimelineModel.WarningType.V8Deopt);
         break;
     case recordTypes.TimerFire:
     case recordTypes.TimerInstall:
@@ -2049,36 +2049,49 @@
     },
 
     /**
-     * @param {?string} warningType
      * @param {!WebInspector.TracingModel.Event} event
+     * @param {string=} warningType
      */
-    appendWarningRow: function(warningType, event)
+    appendWarningRow: function(event, warningType)
     {
-
-        var warnings = WebInspector.TimelineModel.WarningType;
-        var span = createElement("span");
-        var eventData = event.args["data"];
-
-        switch (warningType) {
-        case warnings.ForcedStyle:
-        case warnings.ForcedLayout:
-            span.appendChild(WebInspector.linkifyDocumentationURLAsNode("../../fundamentals/performance/rendering/avoid-large-complex-layouts-and-layout-thrashing#avoid-forced-synchronous-layouts",
-                WebInspector.UIString("Forced reflow")));
-            span.createTextChild(WebInspector.UIString(" is a likely performance bottleneck."));
-            break;
-        case warnings.IdleDeadlineExceeded:
-            span.textContent = WebInspector.UIString("Idle callback execution extended beyond deadline by " +
-                Number.millisToString(event.duration - eventData["allottedMilliseconds"], true));
-            break;
-        case warnings.V8Deopt:
-            span.appendChild(WebInspector.linkifyURLAsNode("https://github.com/GoogleChrome/devtools-docs/issues/53",
-                WebInspector.UIString("Not optimized"), undefined, true));
-            span.createTextChild(WebInspector.UIString(": %s", eventData["deoptReason"]));
-            break;
-        default:
-            console.assert(false, "Unhandled TimelineModel.WarningType");
-        }
-
-        this.appendElementRow(WebInspector.UIString("Warning"), span, true);
+        var warning = WebInspector.TimelineUIUtils.eventWarning(event, warningType);
+        if (warning)
+            this.appendElementRow(WebInspector.UIString("Warning"), warning, true);
     }
 }
+
+/**
+ * @param {!WebInspector.TracingModel.Event} event
+ * @param {string=} warningType
+ * @return {?Element}
+ */
+WebInspector.TimelineUIUtils.eventWarning = function(event, warningType)
+{
+    var warning = warningType || event.warning;
+    if (!warning)
+        return null;
+    var warnings = WebInspector.TimelineModel.WarningType;
+    var span = createElement("span");
+    var eventData = event.args["data"];
+
+    switch (warning) {
+    case warnings.ForcedStyle:
+    case warnings.ForcedLayout:
+        span.appendChild(WebInspector.linkifyDocumentationURLAsNode("../../fundamentals/performance/rendering/avoid-large-complex-layouts-and-layout-thrashing#avoid-forced-synchronous-layouts",
+            WebInspector.UIString("Forced reflow")));
+        span.createTextChild(WebInspector.UIString(" is a likely performance bottleneck."));
+        break;
+    case warnings.IdleDeadlineExceeded:
+        span.textContent = WebInspector.UIString("Idle callback execution extended beyond deadline by " +
+            Number.millisToString(event.duration - eventData["allottedMilliseconds"], true));
+        break;
+    case warnings.V8Deopt:
+        span.appendChild(WebInspector.linkifyURLAsNode("https://github.com/GoogleChrome/devtools-docs/issues/53",
+            WebInspector.UIString("Not optimized"), undefined, true));
+        span.createTextChild(WebInspector.UIString(": %s", eventData["deoptReason"]));
+        break;
+    default:
+        console.assert(false, "Unhandled TimelineModel.WarningType");
+    }
+    return span;
+}
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/module.json b/third_party/WebKit/Source/devtools/front_end/timeline/module.json
index 8cd9613..7977911 100644
--- a/third_party/WebKit/Source/devtools/front_end/timeline/module.json
+++ b/third_party/WebKit/Source/devtools/front_end/timeline/module.json
@@ -123,6 +123,7 @@
     ],
     "resources": [
         "invalidationsTree.css",
+        "timelineFlamechartPopover.css",
         "timelinePanel.css",
         "timelineStatusDialog.css"
     ]
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/timelineFlamechartPopover.css b/third_party/WebKit/Source/devtools/front_end/timeline/timelineFlamechartPopover.css
new file mode 100644
index 0000000..4d5ca1ef
--- /dev/null
+++ b/third_party/WebKit/Source/devtools/front_end/timeline/timelineFlamechartPopover.css
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 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.
+ */
+
+.timeline-flamechart-popover span {
+    margin-right: 5px;
+}
+
+.timeline-flamechart-popover span.timeline-info-network-time {
+    color: #009;
+}
+
+.timeline-flamechart-popover span.timeline-info-time {
+    color: #282;
+}
+
+.timeline-flamechart-popover span.timeline-info-warning {
+    color: #e44;
+}
+
+.timeline-flamechart-popover span.timeline-info-warning * {
+    color: inherit;
+}
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/UIUtils.js b/third_party/WebKit/Source/devtools/front_end/ui/UIUtils.js
index 2d84d8cd..68aff2e 100644
--- a/third_party/WebKit/Source/devtools/front_end/ui/UIUtils.js
+++ b/third_party/WebKit/Source/devtools/front_end/ui/UIUtils.js
@@ -1640,7 +1640,6 @@
      * Theming API is primarily targeted at making dark theme look good.
      * - If rule has ".-theme-preserve" in selector, it won't be affected.
      * - If rule has ".selection" or "selected" or "-theme-selection-color" in selector, its hue is rotated 180deg in dark themes.
-     * - If rule has "highlight" its lightness is dimmmed 50%.
      * - One can create specializations for dark themes via body.-theme-with-dark-background selector in host context.
      */
     _patchProperty: function(selectorText, style, name, output)
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/inspectorCommon.css b/third_party/WebKit/Source/devtools/front_end/ui/inspectorCommon.css
index 4d28d42..fa2794d6 100644
--- a/third_party/WebKit/Source/devtools/front_end/ui/inspectorCommon.css
+++ b/third_party/WebKit/Source/devtools/front_end/ui/inspectorCommon.css
@@ -157,6 +157,10 @@
     background-color: white;
 }
 
+:host-context(.-theme-with-dark-background) input[type="checkbox"] {
+    -webkit-filter: invert(80%);
+}
+
 input[type="search"]:focus,
 input[type="text"]:focus {
     outline: auto 5px -webkit-focus-ring-color;
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/inspectorSyntaxHighlightDark.css b/third_party/WebKit/Source/devtools/front_end/ui/inspectorSyntaxHighlightDark.css
index e4ccf58..e661aa2 100644
--- a/third_party/WebKit/Source/devtools/front_end/ui/inspectorSyntaxHighlightDark.css
+++ b/third_party/WebKit/Source/devtools/front_end/ui/inspectorSyntaxHighlightDark.css
@@ -67,6 +67,6 @@
 .webkit-css-important{color:rgb(255, 26, 26);}
 .webkit-css-keyword{color:rgb(255, 163, 79);}
 .webkit-css-number{color:rgb(217, 217, 217);}
-.webkit-css-property{color:rgb(132, 240, 255);}
+.webkit-css-property{color: rgb(53, 212, 199);}
 .webkit-css-string{color:rgb(231, 194, 111);}
 .webkit-css-url{color:rgb(231, 194, 111);}
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/searchableView.css b/third_party/WebKit/Source/devtools/front_end/ui/searchableView.css
index e346e55..1ca26aa32 100644
--- a/third_party/WebKit/Source/devtools/front_end/ui/searchableView.css
+++ b/third_party/WebKit/Source/devtools/front_end/ui/searchableView.css
@@ -103,6 +103,10 @@
     border-left: 1px solid rgb(163, 163, 163);
 }
 
+:host-context(.-theme-with-dark-background) .toolbar-search-navigation {
+    -webkit-filter: invert(90%);
+}
+
 .toolbar-search-navigation.toolbar-search-navigation-prev.enabled:active {
     background-image: url(Images/searchPrev.png), linear-gradient(rgb(168, 168, 168), rgb(116, 116, 116));
 }
diff --git a/third_party/WebKit/Source/devtools/front_end/ui_lazy/FlameChart.js b/third_party/WebKit/Source/devtools/front_end/ui_lazy/FlameChart.js
index bf76eb6..378e631 100644
--- a/third_party/WebKit/Source/devtools/front_end/ui_lazy/FlameChart.js
+++ b/third_party/WebKit/Source/devtools/front_end/ui_lazy/FlameChart.js
@@ -447,12 +447,22 @@
 
 WebInspector.FlameChart.prototype = {
     /**
+     * @override
+     */
+    willHide: function()
+    {
+        this.hideHighlight();
+    },
+
+    /**
      * @param {number} entryIndex
      */
     highlightEntry: function(entryIndex)
     {
-        this._entryInfo.removeChildren();
-        this._innerHighlightEntry(entryIndex);
+        if (this._highlightedEntryIndex === entryIndex)
+            return;
+        this._highlightedEntryIndex = entryIndex;
+        this._updateElementPosition(this._highlightElement, this._highlightedEntryIndex);
     },
 
     hideHighlight: function()
@@ -539,6 +549,7 @@
         }
 
         this._cancelAnimation();
+        this._updateHighlight();
         this._cancelWindowTimesAnimation = WebInspector.animateFunction(this.element.window(), this._animateWindowTimes.bind(this),
             [{from: this._timeWindowLeft, to: startTime}, {from: this._timeWindowRight, to: endTime}], 5,
             this._animationCompleted.bind(this));
@@ -554,12 +565,14 @@
     {
         this._timeWindowLeft = startTime;
         this._timeWindowRight = endTime;
+        this._updateHighlight();
         this.update();
     },
 
     _animationCompleted: function()
     {
         delete this._cancelWindowTimesAnimation;
+        this._updateHighlight();
     },
 
     /**
@@ -609,6 +622,7 @@
         this._dragStartWindowLeft = this._timeWindowLeft;
         this._dragStartWindowRight = this._timeWindowRight;
         this._canvas.style.cursor = "";
+        this.hideHighlight();
         return true;
     },
 
@@ -631,6 +645,7 @@
     _endCanvasDragging: function()
     {
         this._isDragging = false;
+        this._updateHighlight();
     },
 
     /**
@@ -651,6 +666,7 @@
         style.width = "1px";
         this._selectedTimeSpanLabel.textContent = "";
         this._selectionOverlay.classList.remove("hidden");
+        this.hideHighlight();
         return true;
     },
 
@@ -658,6 +674,7 @@
     {
         this._isDragging = false;
         this._flameChartDelegate.endRangeSelection();
+        this._updateHighlight();
     },
 
     _hideRangeSelection: function()
@@ -699,15 +716,17 @@
     {
         this._lastMouseOffsetX = event.offsetX;
         this._lastMouseOffsetY = event.offsetY;
-
         if (!this._enabled())
             return;
-
         if (this._isDragging)
             return;
+        this._updateHighlight();
+    },
 
-        var inDividersBar = event.offsetY < WebInspector.FlameChart.DividersBarHeight;
-        this._highlightedMarkerIndex = inDividersBar ? this._markerIndexAtPosition(event.offsetX) : -1;
+    _updateHighlight: function()
+    {
+        var inDividersBar = this._lastMouseOffsetY < WebInspector.FlameChart.DividersBarHeight;
+        this._highlightedMarkerIndex = inDividersBar ? this._markerIndexAtPosition(this._lastMouseOffsetX) : -1;
         this._updateMarkerHighlight();
 
         var entryIndex = this._coordinatesToEntryIndex(this._lastMouseOffsetX, this._lastMouseOffsetY);
@@ -715,21 +734,22 @@
             this.hideHighlight();
             return;
         }
-        this._updateEntryInfo(entryIndex);
-
+        this._updatePopover(entryIndex);
         this._canvas.style.cursor = this._dataProvider.canJumpToEntry(entryIndex) ? "pointer" : "default";
-        this._innerHighlightEntry(entryIndex);
+        this.highlightEntry(entryIndex);
     },
 
     _onMouseOut: function()
     {
+        this._lastMouseOffsetX = -1;
+        this._lastMouseOffsetY = -1;
         this.hideHighlight();
     },
 
     /**
      * @param {number} entryIndex
      */
-    _updateEntryInfo: function(entryIndex)
+    _updatePopover: function(entryIndex)
     {
         if (entryIndex !== this._highlightedEntryIndex) {
             this._entryInfo.removeChildren();
@@ -759,17 +779,6 @@
         this._entryInfo.style.top = y + "px";
     },
 
-    /**
-     * @param {number} entryIndex
-     */
-    _innerHighlightEntry: function(entryIndex)
-    {
-        if (this._highlightedEntryIndex === entryIndex)
-            return;
-        this._highlightedEntryIndex = entryIndex;
-        this._updateElementPosition(this._highlightElement, this._highlightedEntryIndex);
-    },
-
     _onClick: function()
     {
         this.focus();
@@ -975,6 +984,8 @@
      */
     _coordinatesToEntryIndex: function(x, y)
     {
+        if (x < 0 || y < 0)
+            return -1;
         y += this._scrollTop;
         var timelineData = this._timelineData();
         if (!timelineData)
@@ -1583,6 +1594,8 @@
         this._updateBoundaries();
         this._calculator._updateBoundaries(this);
         this._draw(this._offsetWidth, this._offsetHeight);
+        if (!this._isDragging)
+            this._updateHighlight();
     },
 
     reset: function()
diff --git a/third_party/WebKit/Source/devtools/front_end/ui_lazy/dataGrid.css b/third_party/WebKit/Source/devtools/front_end/ui_lazy/dataGrid.css
index 8036f8d..c8f9f851 100644
--- a/third_party/WebKit/Source/devtools/front_end/ui_lazy/dataGrid.css
+++ b/third_party/WebKit/Source/devtools/front_end/ui_lazy/dataGrid.css
@@ -138,7 +138,13 @@
     position: relative;
 }
 
-.data-grid th.sortable:active {
+.data-grid th.sortable:active::after {
+    content: "";
+    position: absolute;
+    left: 0;
+    right: 0;
+    top: 0;
+    bottom: 0;
     background-color: rgba(0, 0, 0, 0.15);
 }
 
diff --git a/third_party/WebKit/Source/devtools/front_end/ui_lazy/flameChart.css b/third_party/WebKit/Source/devtools/front_end/ui_lazy/flameChart.css
index e417ff2..fd7176c9 100644
--- a/third_party/WebKit/Source/devtools/front_end/ui_lazy/flameChart.css
+++ b/third_party/WebKit/Source/devtools/front_end/ui_lazy/flameChart.css
@@ -84,7 +84,3 @@
 .flame-chart-entry-info table tr td span {
     margin-right: 5px;
 }
-
-.flame-chart-entry-info table tr td span.timeline-network-info-duration {
-    color: darkblue;
-}
diff --git a/third_party/WebKit/Source/devtools/front_end/workspace/IsolatedFileSystem.js b/third_party/WebKit/Source/devtools/front_end/workspace/IsolatedFileSystem.js
index 5208e4a..1d5d957 100644
--- a/third_party/WebKit/Source/devtools/front_end/workspace/IsolatedFileSystem.js
+++ b/third_party/WebKit/Source/devtools/front_end/workspace/IsolatedFileSystem.js
@@ -283,39 +283,6 @@
 
     /**
      * @param {string} path
-     * @param {function(?Date, ?number)} callback
-     */
-    requestMetadata: function(path, callback)
-    {
-        this._domFileSystem.root.getFile(path, null, fileEntryLoaded, errorHandler);
-
-        /**
-         * @param {!FileEntry} entry
-         */
-        function fileEntryLoaded(entry)
-        {
-            entry.getMetadata(successHandler, errorHandler);
-        }
-
-        /**
-         * @param {!Metadata} metadata
-         */
-        function successHandler(metadata)
-        {
-            callback(metadata.modificationTime, metadata.size);
-        }
-
-        /**
-         * @param {!FileError} error
-         */
-        function errorHandler(error)
-        {
-            callback(null, null);
-        }
-    },
-
-    /**
-     * @param {string} path
      * @param {function(?string)} callback
      */
     requestFileContent: function(path, callback)
diff --git a/third_party/WebKit/Source/devtools/front_end/workspace/UISourceCode.js b/third_party/WebKit/Source/devtools/front_end/workspace/UISourceCode.js
index 80e9b53..8b037012 100644
--- a/third_party/WebKit/Source/devtools/front_end/workspace/UISourceCode.js
+++ b/third_party/WebKit/Source/devtools/front_end/workspace/UISourceCode.js
@@ -136,6 +136,14 @@
     /**
      * @return {boolean}
      */
+    isFromServiceProject: function()
+    {
+        return WebInspector.Project.isServiceProject(this._project);
+    },
+
+    /**
+     * @return {boolean}
+     */
     canRename: function()
     {
         return this._project.canRename();
@@ -212,14 +220,6 @@
     },
 
     /**
-     * @param {function(?Date, ?number)} callback
-     */
-    requestMetadata: function(callback)
-    {
-        this._project.requestMetadata(this, callback);
-    },
-
-    /**
      * @override
      * @param {function(?string)} callback
      */
diff --git a/third_party/WebKit/Source/devtools/front_end/workspace/Workspace.js b/third_party/WebKit/Source/devtools/front_end/workspace/Workspace.js
index a81a122..b3423cb3 100644
--- a/third_party/WebKit/Source/devtools/front_end/workspace/Workspace.js
+++ b/third_party/WebKit/Source/devtools/front_end/workspace/Workspace.js
@@ -62,33 +62,30 @@
 }
 
 /**
- * @constructor
- * @param {string} parentPath
- * @param {string} name
- * @param {string} originURL
- * @param {!WebInspector.ResourceType} contentType
+ * @interface
  */
-WebInspector.FileDescriptor = function(parentPath, name, originURL, contentType)
-{
-    this.parentPath = parentPath;
-    this.name = name;
-    this.originURL = originURL;
-    this.contentType = contentType;
-}
+WebInspector.Project = function() { }
 
 /**
- * @interface
- * @extends {WebInspector.EventTarget}
+ * @param {!WebInspector.Project} project
+ * @return {boolean}
  */
-WebInspector.ProjectDelegate = function() { }
-
-WebInspector.ProjectDelegate.Events = {
-    FileAdded: "FileAdded",
-    FileRemoved: "FileRemoved",
-    FileChanged: "FileChanged"
+WebInspector.Project.isServiceProject = function(project)
+{
+    return project.type() === WebInspector.projectTypes.Debugger || project.type() === WebInspector.projectTypes.Formatter || project.type() === WebInspector.projectTypes.Service;
 }
 
-WebInspector.ProjectDelegate.prototype = {
+WebInspector.Project.prototype = {
+    /**
+     * @return {!WebInspector.Workspace}
+     */
+    workspace: function() { },
+
+    /**
+     * @return {string}
+     */
+    id: function() { },
+
     /**
      * @return {string}
      */
@@ -105,16 +102,10 @@
     url: function() { },
 
     /**
-     * @param {string} path
-     * @param {function(?Date, ?number)} callback
-     */
-    requestMetadata: function(path, callback) { },
-
-    /**
-     * @param {string} path
+     * @param {!WebInspector.UISourceCode} uiSourceCode
      * @param {function(?string)} callback
      */
-    requestFileContent: function(path, callback) { },
+    requestFileContent: function(uiSourceCode, callback) { },
 
     /**
      * @return {boolean}
@@ -122,11 +113,11 @@
     canSetFileContent: function() { },
 
     /**
-     * @param {string} path
+     * @param {!WebInspector.UISourceCode} uiSourceCode
      * @param {string} newContent
      * @param {function(?string)} callback
      */
-    setFileContent: function(path, newContent, callback) { },
+    setFileContent: function(uiSourceCode, newContent, callback) { },
 
     /**
      * @return {boolean}
@@ -134,11 +125,11 @@
     canRename: function() { },
 
     /**
-     * @param {string} path
+     * @param {!WebInspector.UISourceCode} uiSourceCode
      * @param {string} newName
      * @param {function(boolean, string=, string=, !WebInspector.ResourceType=)} callback
      */
-    rename: function(path, newName, callback) { },
+    rename: function(uiSourceCode, newName, callback) { },
 
     /**
      * @param {string} path
@@ -155,7 +146,7 @@
      * @param {string} path
      * @param {?string} name
      * @param {string} content
-     * @param {function(?string)} callback
+     * @param {function(?WebInspector.UISourceCode)} callback
      */
     createFile: function(path, name, content, callback) { },
 
@@ -167,13 +158,13 @@
     remove: function() { },
 
     /**
-     * @param {string} path
+     * @param {!WebInspector.UISourceCode} uiSourceCode
      * @param {string} query
      * @param {boolean} caseSensitive
      * @param {boolean} isRegex
      * @param {function(!Array.<!WebInspector.ContentProvider.SearchMatch>)} callback
      */
-    searchInFileContent: function(path, query, caseSensitive, isRegex, callback) { },
+    searchInFileContent: function(uiSourceCode, query, caseSensitive, isRegex, callback) { },
 
     /**
      * @param {!WebInspector.ProjectSearchConfig} searchConfig
@@ -186,46 +177,70 @@
     /**
      * @param {!WebInspector.Progress} progress
      */
-    indexContent: function(progress) { }
-}
+    indexContent: function(progress) { },
 
-/**
- * @constructor
- * @extends {WebInspector.Object}
- * @param {!WebInspector.Workspace} workspace
- * @param {string} projectId
- * @param {!WebInspector.ProjectDelegate} projectDelegate
- */
-WebInspector.Project = function(workspace, projectId, projectDelegate)
-{
-    /** @type {!Map.<string, !{uiSourceCode: !WebInspector.UISourceCode, index: number}>} */
-    this._uiSourceCodesMap = new Map();
-    /** @type {!Array.<!WebInspector.UISourceCode>} */
-    this._uiSourceCodesList = [];
-    this._workspace = workspace;
-    this._projectId = projectId;
-    this._projectDelegate = projectDelegate;
-    this._url = this._projectDelegate.url();
-    this._displayName = this._projectDelegate.displayName();
-    projectDelegate.addEventListener(WebInspector.ProjectDelegate.Events.FileAdded, this._fileAdded, this);
-    projectDelegate.addEventListener(WebInspector.ProjectDelegate.Events.FileRemoved, this._fileRemoved, this);
-    projectDelegate.addEventListener(WebInspector.ProjectDelegate.Events.FileChanged, this._fileChanged, this);
+    /**
+     * @param {string} path
+     * @return {?WebInspector.UISourceCode}
+     */
+    uiSourceCode: function(path) { },
+
+    /**
+     * @param {string} originURL
+     * @return {?WebInspector.UISourceCode}
+     */
+    uiSourceCodeForOriginURL: function(originURL) { },
+
+    /**
+     * @return {!Array.<!WebInspector.UISourceCode>}
+     */
+    uiSourceCodes: function() { }
 }
 
 /**
  * @enum {string}
  */
-WebInspector.Project.Events = {
-    DisplayNameUpdated: "DisplayNameUpdated"
-};
+WebInspector.projectTypes = {
+    Debugger: "debugger",
+    Formatter: "formatter",
+    Network: "network",
+    Snippets: "snippets",
+    FileSystem: "filesystem",
+    ContentScripts: "contentscripts",
+    Service: "service"
+}
 
-WebInspector.Project.prototype = {
+/**
+ * @constructor
+ * @param {!WebInspector.Workspace} workspace
+ * @param {string} id
+ * @param {!WebInspector.projectTypes} type
+ * @param {string} url
+ * @param {string} displayName
+ */
+WebInspector.ProjectStore = function(workspace, id, type, url, displayName)
+{
+    this._workspace = workspace;
+    this._id = id;
+    this._type = type;
+    this._url = url;
+    this._displayName = displayName;
+
+    /** @type {!Map.<string, !{uiSourceCode: !WebInspector.UISourceCode, index: number}>} */
+    this._uiSourceCodesMap = new Map();
+    /** @type {!Array.<!WebInspector.UISourceCode>} */
+    this._uiSourceCodesList = [];
+
+    this._project = /** @type {!WebInspector.Project} */(this);
+}
+
+WebInspector.ProjectStore.prototype = {
     /**
      * @return {string}
      */
     id: function()
     {
-        return this._projectId;
+        return this._id;
     },
 
     /**
@@ -233,26 +248,7 @@
      */
     type: function()
     {
-        return this._projectDelegate.type();
-    },
-
-    /**
-     * @return {string}
-     */
-    displayName: function()
-    {
-        return this._displayName;
-    },
-
-    /**
-     * @param {string} displayName
-     */
-    setDisplayName: function(displayName)
-    {
-        if (this._displayName === displayName)
-            return;
-        this._displayName = displayName;
-        this.dispatchEventToListeners(WebInspector.Project.Events.DisplayNameUpdated);
+        return this._type;
     },
 
     /**
@@ -264,56 +260,45 @@
     },
 
     /**
-     * @return {boolean}
+     * @return {string}
      */
-    isServiceProject: function()
+    displayName: function()
     {
-        return this._projectDelegate.type() === WebInspector.projectTypes.Debugger || this._projectDelegate.type() === WebInspector.projectTypes.Formatter || this._projectDelegate.type() === WebInspector.projectTypes.Service;
+        return this._displayName;
     },
 
+    /**
+     * @return {!WebInspector.Workspace}
+     */
+    workspace: function()
+    {
+        return this._workspace;
+    },
 
     /**
-     * @param {!WebInspector.Event} event
+     * @param {string} parentPath
+     * @param {string} name
+     * @param {string} originURL
+     * @param {!WebInspector.ResourceType} contentType
+     * @return {!WebInspector.UISourceCode}
      */
-    _fileAdded: function(event)
+    addUISourceCode: function(parentPath, name, originURL, contentType)
     {
-        var fileDescriptor = /** @type {!WebInspector.FileDescriptor} */ (event.data);
-        var path = fileDescriptor.parentPath ? fileDescriptor.parentPath + "/" + fileDescriptor.name : fileDescriptor.name;
+        var path = parentPath ? parentPath + "/" + name : name;
         var uiSourceCode = this.uiSourceCode(path);
         if (uiSourceCode)
-            return;
-
-        uiSourceCode = new WebInspector.UISourceCode(this, fileDescriptor.parentPath, fileDescriptor.name, fileDescriptor.originURL, fileDescriptor.contentType);
-
+            return uiSourceCode;
+        uiSourceCode = new WebInspector.UISourceCode(this._project, parentPath, name, originURL, contentType);
         this._uiSourceCodesMap.set(path, {uiSourceCode: uiSourceCode, index: this._uiSourceCodesList.length});
         this._uiSourceCodesList.push(uiSourceCode);
         this._workspace.dispatchEventToListeners(WebInspector.Workspace.Events.UISourceCodeAdded, uiSourceCode);
-    },
-
-    /**
-     * @param {!WebInspector.Event} event
-     */
-    _fileRemoved: function(event)
-    {
-        var path = /** @type {string} */ (event.data);
-        this._removeFile(path);
-    },
-
-    /**
-     * @param {!WebInspector.Event} event
-     */
-    _fileChanged: function(event)
-    {
-        var path = /** @type {string} */ (event.data);
-        var uiSourceCode = this.uiSourceCode(path);
-        if (uiSourceCode)
-            uiSourceCode.checkContentUpdated();
+        return uiSourceCode;
     },
 
     /**
      * @param {string} path
      */
-    _removeFile: function(path)
+    removeUISourceCode: function(path)
     {
         var uiSourceCode = this.uiSourceCode(path);
         if (!uiSourceCode)
@@ -329,24 +314,14 @@
         this._workspace.dispatchEventToListeners(WebInspector.Workspace.Events.UISourceCodeRemoved, entry.uiSourceCode);
     },
 
-    _remove: function()
+    removeProject: function()
     {
-        this._projectDelegate.removeEventListener(WebInspector.ProjectDelegate.Events.FileAdded, this._fileAdded, this);
-        this._projectDelegate.removeEventListener(WebInspector.ProjectDelegate.Events.FileRemoved, this._fileRemoved, this);
-        this._workspace.dispatchEventToListeners(WebInspector.Workspace.Events.ProjectRemoved, this);
+        this._workspace._removeProject(this._project);
         this._uiSourceCodesMap = new Map();
         this._uiSourceCodesList = [];
     },
 
     /**
-     * @return {!WebInspector.Workspace}
-     */
-    workspace: function()
-    {
-        return this._workspace;
-    },
-
-    /**
      * @param {string} path
      * @return {?WebInspector.UISourceCode}
      */
@@ -380,181 +355,16 @@
 
     /**
      * @param {!WebInspector.UISourceCode} uiSourceCode
-     * @param {function(?Date, ?number)} callback
-     */
-    requestMetadata: function(uiSourceCode, callback)
-    {
-        this._projectDelegate.requestMetadata(uiSourceCode.path(), callback);
-    },
-
-    /**
-     * @param {!WebInspector.UISourceCode} uiSourceCode
-     * @param {function(?string)} callback
-     */
-    requestFileContent: function(uiSourceCode, callback)
-    {
-        this._projectDelegate.requestFileContent(uiSourceCode.path(), callback);
-    },
-
-    /**
-     * @return {boolean}
-     */
-    canSetFileContent: function()
-    {
-        return this._projectDelegate.canSetFileContent();
-    },
-
-    /**
-     * @param {!WebInspector.UISourceCode} uiSourceCode
-     * @param {string} newContent
-     * @param {function(?string)} callback
-     */
-    setFileContent: function(uiSourceCode, newContent, callback)
-    {
-        this._projectDelegate.setFileContent(uiSourceCode.path(), newContent, callback);
-    },
-
-    /**
-     * @return {boolean}
-     */
-    canRename: function()
-    {
-        return this._projectDelegate.canRename();
-    },
-
-    /**
-     * @param {!WebInspector.UISourceCode} uiSourceCode
      * @param {string} newName
-     * @param {function(boolean, string=, string=, !WebInspector.ResourceType=)} callback
      */
-    rename: function(uiSourceCode, newName, callback)
+    renameUISourceCode: function(uiSourceCode, newName)
     {
-        if (newName === uiSourceCode.name()) {
-            callback(true, uiSourceCode.name(), uiSourceCode.originURL(), uiSourceCode.contentType());
-            return;
-        }
-
-        this._projectDelegate.rename(uiSourceCode.path(), newName, innerCallback.bind(this));
-
-        /**
-         * @param {boolean} success
-         * @param {string=} newName
-         * @param {string=} newOriginURL
-         * @param {!WebInspector.ResourceType=} newContentType
-         * @this {WebInspector.Project}
-         */
-        function innerCallback(success, newName, newOriginURL, newContentType)
-        {
-            if (!success || !newName) {
-                callback(false);
-                return;
-            }
-            var oldPath = uiSourceCode.path();
-            var newPath = uiSourceCode.parentPath() ? uiSourceCode.parentPath() + "/" + newName : newName;
-            var value = /** @type {!{uiSourceCode: !WebInspector.UISourceCode, index: number}} */ (this._uiSourceCodesMap.get(oldPath));
-            this._uiSourceCodesMap.set(newPath, value);
-            this._uiSourceCodesMap.delete(oldPath);
-            callback(true, newName, newOriginURL, newContentType);
-        }
-    },
-
-    /**
-     * @param {string} path
-     * @param {function()=} callback
-     */
-    refresh: function(path, callback)
-    {
-        this._projectDelegate.refresh(path, callback);
-    },
-
-    /**
-     * @param {string} path
-     */
-    excludeFolder: function(path)
-    {
-        this._projectDelegate.excludeFolder(path);
-        var uiSourceCodes = this._uiSourceCodesList.slice();
-        for (var i = 0; i < uiSourceCodes.length; ++i) {
-            var uiSourceCode = uiSourceCodes[i];
-            if (uiSourceCode.path().startsWith(path.substr(1)))
-                this._removeFile(uiSourceCode.path());
-        }
-    },
-
-    /**
-     * @param {string} path
-     * @param {?string} name
-     * @param {string} content
-     * @param {function(?string)} callback
-     */
-    createFile: function(path, name, content, callback)
-    {
-        this._projectDelegate.createFile(path, name, content, innerCallback);
-
-        function innerCallback(filePath)
-        {
-            callback(filePath);
-        }
-    },
-
-    /**
-     * @param {string} path
-     */
-    deleteFile: function(path)
-    {
-        this._projectDelegate.deleteFile(path);
-    },
-
-    remove: function()
-    {
-        this._projectDelegate.remove();
-    },
-
-    /**
-     * @param {!WebInspector.UISourceCode} uiSourceCode
-     * @param {string} query
-     * @param {boolean} caseSensitive
-     * @param {boolean} isRegex
-     * @param {function(!Array.<!WebInspector.ContentProvider.SearchMatch>)} callback
-     */
-    searchInFileContent: function(uiSourceCode, query, caseSensitive, isRegex, callback)
-    {
-        this._projectDelegate.searchInFileContent(uiSourceCode.path(), query, caseSensitive, isRegex, callback);
-    },
-
-    /**
-     * @param {!WebInspector.ProjectSearchConfig} searchConfig
-     * @param {!Array.<string>} filesMathingFileQuery
-     * @param {!WebInspector.Progress} progress
-     * @param {function(!Array.<string>)} callback
-     */
-    findFilesMatchingSearchRequest: function(searchConfig, filesMathingFileQuery, progress, callback)
-    {
-        this._projectDelegate.findFilesMatchingSearchRequest(searchConfig, filesMathingFileQuery, progress, callback);
-    },
-
-    /**
-     * @param {!WebInspector.Progress} progress
-     */
-    indexContent: function(progress)
-    {
-        this._projectDelegate.indexContent(progress);
-    },
-
-    __proto__: WebInspector.Object.prototype
-}
-
-/**
- * @enum {string}
- */
-WebInspector.projectTypes = {
-    Debugger: "debugger",
-    Formatter: "formatter",
-    Network: "network",
-    Snippets: "snippets",
-    FileSystem: "filesystem",
-    ContentScripts: "contentscripts",
-    Service: "service"
+        var oldPath = uiSourceCode.path();
+        var newPath = uiSourceCode.parentPath() ? uiSourceCode.parentPath() + "/" + newName : newName;
+        var value = /** @type {!{uiSourceCode: !WebInspector.UISourceCode, index: number}} */ (this._uiSourceCodesMap.get(oldPath));
+        this._uiSourceCodesMap.set(newPath, value);
+        this._uiSourceCodesMap.delete(oldPath);
+    }
 }
 
 /**
@@ -563,8 +373,8 @@
  */
 WebInspector.Workspace = function()
 {
-    /** @type {!Object.<string, !WebInspector.Project>} */
-    this._projects = {};
+    /** @type {!Map<string, !WebInspector.Project>} */
+    this._projects = new Map();
     this._hasResourceContentTrackingExtensions = false;
 }
 
@@ -608,7 +418,7 @@
      */
     uiSourceCode: function(projectId, path)
     {
-        var project = this._projects[projectId];
+        var project = this._projects.get(projectId);
         return project ? project.uiSourceCode(path) : null;
     },
 
@@ -620,8 +430,7 @@
     {
         var projects = this.projectsForType(WebInspector.projectTypes.Network);
         projects = projects.concat(this.projectsForType(WebInspector.projectTypes.ContentScripts));
-        for (var i = 0; i < projects.length; ++i) {
-            var project = projects[i];
+        for (var project of projects) {
             var uiSourceCode = project.uiSourceCodeForOriginURL(originURL);
             if (uiSourceCode)
                 return uiSourceCode;
@@ -635,9 +444,7 @@
      */
     filesystemUISourceCode: function(originURL)
     {
-        var projects = this.projectsForType(WebInspector.projectTypes.FileSystem);
-        for (var i = 0; i < projects.length; ++i) {
-            var project = projects[i];
+        for (var project of this.projectsForType(WebInspector.projectTypes.FileSystem)) {
             var uiSourceCode = project.uiSourceCodeForOriginURL(originURL);
             if (uiSourceCode)
                 return uiSourceCode;
@@ -652,8 +459,7 @@
     uiSourceCodesForProjectType: function(type)
     {
         var result = [];
-        for (var projectName in this._projects) {
-            var project = this._projects[projectName];
+        for (var project of this._projects.values()) {
             if (project.type() === type)
                 result = result.concat(project.uiSourceCodes());
         }
@@ -661,37 +467,30 @@
     },
 
     /**
-     * @param {string} projectId
-     * @param {!WebInspector.ProjectDelegate} projectDelegate
-     * @return {!WebInspector.Project}
+     * @param {!WebInspector.Project} project
      */
-    addProject: function(projectId, projectDelegate)
+    addProject: function(project)
     {
-        var project = new WebInspector.Project(this, projectId, projectDelegate);
-        this._projects[projectId] = project;
+        this._projects.set(project.id(), project);
         this.dispatchEventToListeners(WebInspector.Workspace.Events.ProjectAdded, project);
-        return project;
     },
 
     /**
-     * @param {string} projectId
+     * @param {!WebInspector.Project} project
      */
-    removeProject: function(projectId)
+    _removeProject: function(project)
     {
-        var project = this._projects[projectId];
-        if (!project)
-            return;
-        delete this._projects[projectId];
-        project._remove();
+        this._projects.delete(project.id());
+        this.dispatchEventToListeners(WebInspector.Workspace.Events.ProjectRemoved, project);
     },
 
     /**
      * @param {string} projectId
-     * @return {!WebInspector.Project}
+     * @return {?WebInspector.Project}
      */
     project: function(projectId)
     {
-        return this._projects[projectId];
+        return this._projects.get(projectId) || null;
     },
 
     /**
@@ -699,7 +498,7 @@
      */
     projects: function()
     {
-        return Object.values(this._projects);
+        return Array.from(this._projects.values());
     },
 
     /**
@@ -721,10 +520,8 @@
     uiSourceCodes: function()
     {
         var result = [];
-        for (var projectId in this._projects) {
-            var project = this._projects[projectId];
+        for (var project of this._projects.values())
             result = result.concat(project.uiSourceCodes());
-        }
         return result;
     },
 
diff --git a/third_party/WebKit/Source/modules/accessibility/AXNodeObject.cpp b/third_party/WebKit/Source/modules/accessibility/AXNodeObject.cpp
index e343919..d0fc039c 100644
--- a/third_party/WebKit/Source/modules/accessibility/AXNodeObject.cpp
+++ b/third_party/WebKit/Source/modules/accessibility/AXNodeObject.cpp
@@ -1625,11 +1625,8 @@
         return false;
 
     // Step 2A from: http://www.w3.org/TR/accname-aam-1.1
-    if (layoutObject()
-        && layoutObject()->style()->visibility() != VISIBLE
-        && !equalIgnoringCase(getAttribute(aria_hiddenAttr), "false")) {
+    if (isHiddenForTextAlternativeCalculation())
         return false;
-    }
 
     // Step 2B from: http://www.w3.org/TR/accname-aam-1.1
     WillBeHeapVector<RawPtrWillBeMember<Element>> elements;
@@ -2464,7 +2461,8 @@
         for (size_t i = 0; i < relatedObjects.size(); i++)
             descriptionObjects->append(relatedObjects[i]->object);
     }
-    return result;
+
+    return collapseWhitespace(result);
 }
 
 // Based on http://rawgit.com/w3c/aria/master/html-aam/html-aam.html#accessible-name-and-description-calculation
diff --git a/third_party/WebKit/Source/modules/accessibility/AXObject.cpp b/third_party/WebKit/Source/modules/accessibility/AXObject.cpp
index e04b267a..feb0186 100644
--- a/third_party/WebKit/Source/modules/accessibility/AXObject.cpp
+++ b/third_party/WebKit/Source/modules/accessibility/AXObject.cpp
@@ -676,6 +676,19 @@
     return m_cachedIsPresentationalChild;
 }
 
+// Simplify whitespace, but preserve a single leading and trailing whitespace character if it's present.
+// static
+String AXObject::collapseWhitespace(const String& str)
+{
+    StringBuilder result;
+    if (!str.isEmpty() && isHTMLSpace<UChar>(str[0]))
+        result.append(' ');
+    result.append(str.simplifyWhiteSpace(isHTMLSpace<UChar>));
+    if (!str.isEmpty() && isHTMLSpace<UChar>(str[str.length() - 1]))
+        result.append(' ');
+    return result.toString();
+}
+
 String AXObject::computedName() const
 {
     AXNameFrom nameFrom;
@@ -689,8 +702,9 @@
     AXRelatedObjectVector relatedObjects;
     String text = textAlternative(false, false, visited, nameFrom, &relatedObjects, nullptr);
 
-    if (!node() || !isHTMLBRElement(node()))
-        text = text.simplifyWhiteSpace(isHTMLSpace<UChar>, WTF::DoNotStripWhiteSpace);
+    AccessibilityRole role = roleValue();
+    if (!node() || (!isHTMLBRElement(node()) && role != StaticTextRole && role != InlineTextBoxRole))
+        text = collapseWhitespace(text);
 
     if (nameObjects) {
         nameObjects->clear();
@@ -716,6 +730,28 @@
     return axObj.textAlternative(true, inAriaLabelledByTraversal, visited, tmpNameFrom, nullptr, nullptr);
 }
 
+bool AXObject::isHiddenForTextAlternativeCalculation() const
+{
+    if (equalIgnoringCase(getAttribute(aria_hiddenAttr), "false"))
+        return false;
+
+    if (layoutObject())
+        return layoutObject()->style()->visibility() != VISIBLE;
+
+    // This is an obscure corner case: if a node has no LayoutObject, that means it's not rendered,
+    // but we still may be exploring it as part of a text alternative calculation, for example if it
+    // was explicitly referenced by aria-labelledby. So we need to explicitly call the style resolver
+    // to check whether it's invisible or display:none, rather than relying on the style cached in the
+    // LayoutObject.
+    Document* doc = document();
+    if (doc && doc->frame() && node() && node()->isElementNode()) {
+        RefPtr<ComputedStyle> style = doc->ensureStyleResolver().styleForElement(toElement(node()));
+        return style->display() == NONE || style->visibility() != VISIBLE;
+    }
+
+    return false;
+}
+
 String AXObject::ariaTextAlternative(bool recursive, bool inAriaLabelledByTraversal, AXObjectSet& visited, AXNameFrom& nameFrom, AXRelatedObjectVector* relatedObjects, NameSources* nameSources, bool* foundTextAlternative) const
 {
     String textAlternative;
@@ -724,9 +760,8 @@
 
     // Step 2A from: http://www.w3.org/TR/accname-aam-1.1
     // If you change this logic, update AXNodeObject::nameFromLabelElement, too.
-    if (!recursive && layoutObject()
-        && layoutObject()->style()->visibility() != VISIBLE
-        && !equalIgnoringCase(getAttribute(aria_hiddenAttr), "false")) {
+    if (!inAriaLabelledByTraversal && isHiddenForTextAlternativeCalculation()) {
+        *foundTextAlternative = true;
         return String();
     }
 
diff --git a/third_party/WebKit/Source/modules/accessibility/AXObject.h b/third_party/WebKit/Source/modules/accessibility/AXObject.h
index 4ebcb13..94ad5bf 100644
--- a/third_party/WebKit/Source/modules/accessibility/AXObject.h
+++ b/third_party/WebKit/Source/modules/accessibility/AXObject.h
@@ -929,7 +929,9 @@
     LayoutRect m_explicitElementRect;
 
     // Used only inside textAlternative():
+    static String collapseWhitespace(const String&);
     static String recursiveTextAlternative(const AXObject&, bool inAriaLabelledByTraversal, AXObjectSet& visited);
+    bool isHiddenForTextAlternativeCalculation() const;
     String ariaTextAlternative(bool recursive, bool inAriaLabelledByTraversal, AXObjectSet& visited, AXNameFrom&, AXRelatedObjectVector*, NameSources*, bool* foundTextAlternative) const;
     String textFromElements(bool inAriaLabelledByTraversal, AXObjectSet& visited, WillBeHeapVector<RawPtrWillBeMember<Element>>& elements, AXRelatedObjectVector* relatedObjects) const;
     void tokenVectorFromAttribute(Vector<String>&, const QualifiedName&) const;
diff --git a/third_party/WebKit/Source/modules/mediastream/RTCPeerConnection.cpp b/third_party/WebKit/Source/modules/mediastream/RTCPeerConnection.cpp
index d762b2f..38891a8d 100644
--- a/third_party/WebKit/Source/modules/mediastream/RTCPeerConnection.cpp
+++ b/third_party/WebKit/Source/modules/mediastream/RTCPeerConnection.cpp
@@ -41,6 +41,7 @@
 #include "core/dom/ExceptionCode.h"
 #include "core/dom/ExecutionContext.h"
 #include "core/frame/LocalFrame.h"
+#include "core/frame/UseCounter.h"
 #include "core/html/VoidCallback.h"
 #include "core/loader/FrameLoader.h"
 #include "core/loader/FrameLoaderClient.h"
@@ -300,6 +301,11 @@
 
 RTCPeerConnection* RTCPeerConnection::create(ExecutionContext* context, const Dictionary& rtcConfiguration, const Dictionary& mediaConstraints, ExceptionState& exceptionState)
 {
+    if (mediaConstraints.isObject())
+        UseCounter::count(context, UseCounter::RTCPeerConnectionConstructorConstraints);
+    else
+        UseCounter::count(context, UseCounter::RTCPeerConnectionConstructorCompliant);
+
     RTCConfiguration* configuration = parseConfiguration(rtcConfiguration, exceptionState);
     if (exceptionState.hadException())
         return 0;
@@ -361,8 +367,13 @@
     ASSERT(m_closed || m_stopped);
 }
 
-void RTCPeerConnection::createOffer(RTCSessionDescriptionCallback* successCallback, RTCErrorCallback* errorCallback, const Dictionary& rtcOfferOptions, ExceptionState& exceptionState)
+void RTCPeerConnection::createOffer(ExecutionContext* context, RTCSessionDescriptionCallback* successCallback, RTCErrorCallback* errorCallback, const Dictionary& rtcOfferOptions, ExceptionState& exceptionState)
 {
+    if (errorCallback)
+        UseCounter::count(context, UseCounter::RTCPeerConnectionCreateOfferLegacyFailureCallback);
+    else
+        UseCounter::count(context, UseCounter::RTCPeerConnectionCreateOfferLegacyNoFailureCallback);
+
     if (throwExceptionIfSignalingStateClosed(m_signalingState, exceptionState))
         return;
 
@@ -375,18 +386,38 @@
     RTCSessionDescriptionRequest* request = RTCSessionDescriptionRequestImpl::create(executionContext(), this, successCallback, errorCallback);
 
     if (offerOptions) {
+        if (offerOptions->offerToReceiveAudio() != -1 || offerOptions->offerToReceiveVideo() != -1)
+            UseCounter::count(context, UseCounter::RTCPeerConnectionCreateOfferLegacyOfferOptions);
+        else if (errorCallback)
+            UseCounter::count(context, UseCounter::RTCPeerConnectionCreateOfferLegacyCompliant);
+
         m_peerHandler->createOffer(request, offerOptions);
     } else {
         WebMediaConstraints constraints = MediaConstraintsImpl::create(rtcOfferOptions, exceptionState);
         if (exceptionState.hadException())
             return;
 
+        if (!constraints.isEmpty())
+            UseCounter::count(context, UseCounter::RTCPeerConnectionCreateOfferLegacyConstraints);
+        else if (errorCallback)
+            UseCounter::count(context, UseCounter::RTCPeerConnectionCreateOfferLegacyCompliant);
+
         m_peerHandler->createOffer(request, constraints);
     }
 }
 
-void RTCPeerConnection::createAnswer(RTCSessionDescriptionCallback* successCallback, RTCErrorCallback* errorCallback, const Dictionary& mediaConstraints, ExceptionState& exceptionState)
+void RTCPeerConnection::createAnswer(ExecutionContext* context, RTCSessionDescriptionCallback* successCallback, RTCErrorCallback* errorCallback, const Dictionary& mediaConstraints, ExceptionState& exceptionState)
 {
+    if (errorCallback)
+        UseCounter::count(context, UseCounter::RTCPeerConnectionCreateAnswerLegacyFailureCallback);
+    else
+        UseCounter::count(context, UseCounter::RTCPeerConnectionCreateAnswerLegacyNoFailureCallback);
+
+    if (mediaConstraints.isObject())
+        UseCounter::count(context, UseCounter::RTCPeerConnectionCreateAnswerLegacyConstraints);
+    else if (errorCallback)
+        UseCounter::count(context, UseCounter::RTCPeerConnectionCreateAnswerLegacyCompliant);
+
     if (throwExceptionIfSignalingStateClosed(m_signalingState, exceptionState))
         return;
 
@@ -400,8 +431,17 @@
     m_peerHandler->createAnswer(request, constraints);
 }
 
-void RTCPeerConnection::setLocalDescription(RTCSessionDescription* sessionDescription, VoidCallback* successCallback, RTCErrorCallback* errorCallback, ExceptionState& exceptionState)
+void RTCPeerConnection::setLocalDescription(ExecutionContext* context, RTCSessionDescription* sessionDescription, VoidCallback* successCallback, RTCErrorCallback* errorCallback, ExceptionState& exceptionState)
 {
+    if (successCallback && errorCallback) {
+        UseCounter::count(context, UseCounter::RTCPeerConnectionSetLocalDescriptionLegacyCompliant);
+    } else {
+        if (!successCallback)
+            UseCounter::count(context, UseCounter::RTCPeerConnectionSetLocalDescriptionLegacyNoSuccessCallback);
+        if (!errorCallback)
+            UseCounter::count(context, UseCounter::RTCPeerConnectionSetLocalDescriptionLegacyNoFailureCallback);
+    }
+
     if (throwExceptionIfSignalingStateClosed(m_signalingState, exceptionState))
         return;
 
@@ -420,8 +460,17 @@
     return RTCSessionDescription::create(webSessionDescription);
 }
 
-void RTCPeerConnection::setRemoteDescription(RTCSessionDescription* sessionDescription, VoidCallback* successCallback, RTCErrorCallback* errorCallback, ExceptionState& exceptionState)
+void RTCPeerConnection::setRemoteDescription(ExecutionContext* context, RTCSessionDescription* sessionDescription, VoidCallback* successCallback, RTCErrorCallback* errorCallback, ExceptionState& exceptionState)
 {
+    if (successCallback && errorCallback) {
+        UseCounter::count(context, UseCounter::RTCPeerConnectionSetRemoteDescriptionLegacyCompliant);
+    } else {
+        if (!successCallback)
+            UseCounter::count(context, UseCounter::RTCPeerConnectionSetRemoteDescriptionLegacyNoSuccessCallback);
+        if (!errorCallback)
+            UseCounter::count(context, UseCounter::RTCPeerConnectionSetRemoteDescriptionLegacyNoFailureCallback);
+    }
+
     if (throwExceptionIfSignalingStateClosed(m_signalingState, exceptionState))
         return;
 
@@ -683,8 +732,9 @@
     return 0;
 }
 
-void RTCPeerConnection::getStats(RTCStatsCallback* successCallback, MediaStreamTrack* selector)
+void RTCPeerConnection::getStats(ExecutionContext* context, RTCStatsCallback* successCallback, MediaStreamTrack* selector)
 {
+    UseCounter::count(context, UseCounter::RTCPeerConnectionGetStatsLegacyNonCompliant);
     RTCStatsRequest* statsRequest = RTCStatsRequestImpl::create(executionContext(), this, successCallback, selector);
     // FIXME: Add passing selector as part of the statsRequest.
     m_peerHandler->getStats(statsRequest);
diff --git a/third_party/WebKit/Source/modules/mediastream/RTCPeerConnection.h b/third_party/WebKit/Source/modules/mediastream/RTCPeerConnection.h
index f6eefc7..ddbd951d 100644
--- a/third_party/WebKit/Source/modules/mediastream/RTCPeerConnection.h
+++ b/third_party/WebKit/Source/modules/mediastream/RTCPeerConnection.h
@@ -68,14 +68,14 @@
     static RTCPeerConnection* create(ExecutionContext*, const Dictionary&, const Dictionary&, ExceptionState&);
     ~RTCPeerConnection() override;
 
-    void createOffer(RTCSessionDescriptionCallback*, RTCErrorCallback*, const Dictionary&, ExceptionState&);
+    void createOffer(ExecutionContext*, RTCSessionDescriptionCallback*, RTCErrorCallback*, const Dictionary&, ExceptionState&);
 
-    void createAnswer(RTCSessionDescriptionCallback*, RTCErrorCallback*, const Dictionary&, ExceptionState&);
+    void createAnswer(ExecutionContext*, RTCSessionDescriptionCallback*, RTCErrorCallback*, const Dictionary&, ExceptionState&);
 
-    void setLocalDescription(RTCSessionDescription*, VoidCallback*, RTCErrorCallback*, ExceptionState&);
+    void setLocalDescription(ExecutionContext*, RTCSessionDescription*, VoidCallback*, RTCErrorCallback*, ExceptionState&);
     RTCSessionDescription* localDescription();
 
-    void setRemoteDescription(RTCSessionDescription*, VoidCallback*, RTCErrorCallback*, ExceptionState&);
+    void setRemoteDescription(ExecutionContext*, RTCSessionDescription*, VoidCallback*, RTCErrorCallback*, ExceptionState&);
     RTCSessionDescription* remoteDescription();
 
     String signalingState() const;
@@ -105,7 +105,7 @@
 
     void removeStream(MediaStream*, ExceptionState&);
 
-    void getStats(RTCStatsCallback* successCallback, MediaStreamTrack* selector);
+    void getStats(ExecutionContext*, RTCStatsCallback* successCallback, MediaStreamTrack* selector);
 
     RTCDataChannel* createDataChannel(String label, const Dictionary& dataChannelDict, ExceptionState&);
 
diff --git a/third_party/WebKit/Source/modules/mediastream/RTCPeerConnection.idl b/third_party/WebKit/Source/modules/mediastream/RTCPeerConnection.idl
index f42c7b3..ce512b5 100644
--- a/third_party/WebKit/Source/modules/mediastream/RTCPeerConnection.idl
+++ b/third_party/WebKit/Source/modules/mediastream/RTCPeerConnection.idl
@@ -99,20 +99,20 @@
 
     // https://w3c.github.io/webrtc-pc/#legacy-interface-extensions
     // TODO(guidou): The failureCallback argument should be non-optional.
-    [RaisesException] void createOffer(RTCSessionDescriptionCallback successCallback, [Default=Undefined] optional RTCErrorCallback failureCallback, optional Dictionary rtcOfferOptions);
+    [CallWith=ExecutionContext, RaisesException] void createOffer(RTCSessionDescriptionCallback successCallback, [Default=Undefined] optional RTCErrorCallback failureCallback, optional Dictionary rtcOfferOptions);
     // TODO(guidou): None of the arguments should be optional.
-    [RaisesException] void setLocalDescription(RTCSessionDescription description, [Default=Undefined] optional VoidCallback successCallback, [Default=Undefined] optional RTCErrorCallback failureCallback);
+    [CallWith=ExecutionContext, RaisesException] void setLocalDescription(RTCSessionDescription description, [Default=Undefined] optional VoidCallback successCallback, [Default=Undefined] optional RTCErrorCallback failureCallback);
     // TODO(guidou): The failureCallback argument should be non-optional, and
     // there should be no mediaConstraints argument.
-    [RaisesException] void createAnswer(RTCSessionDescriptionCallback successCallback, [Default=Undefined] optional RTCErrorCallback failureCallback, optional Dictionary mediaConstraints);
+    [CallWith=ExecutionContext, RaisesException] void createAnswer(RTCSessionDescriptionCallback successCallback, [Default=Undefined] optional RTCErrorCallback failureCallback, optional Dictionary mediaConstraints);
     // TODO(guidou): The successCallback and failureCallback arguments should be
     // non-optional.
-    [RaisesException] void setRemoteDescription(RTCSessionDescription description, [Default=Undefined] optional VoidCallback successCallback, [Default=Undefined] optional RTCErrorCallback failureCallback);
+    [CallWith=ExecutionContext, RaisesException] void setRemoteDescription(RTCSessionDescription description, [Default=Undefined] optional VoidCallback successCallback, [Default=Undefined] optional RTCErrorCallback failureCallback);
     [RaisesException] void addIceCandidate(RTCIceCandidate candidate, VoidCallback successCallback, RTCErrorCallback failureCallback);
     // TODO(guidou): The selector argument should the first (nullable,
     // non-optional) argument, and there should be a third failureCallback
     // argument.
-    [LegacyInterfaceTypeChecking] void getStats(RTCStatsCallback successCallback, [Default=Undefined] optional MediaStreamTrack selector);
+    [CallWith=ExecutionContext, LegacyInterfaceTypeChecking] void getStats(RTCStatsCallback successCallback, [Default=Undefined] optional MediaStreamTrack selector);
 
     // https://w3c.github.io/webrtc-pc/#peer-to-peer-data-api
     // TODO(guidou): The label argument should have [TreatNullAs=EmptyString]
diff --git a/third_party/WebKit/Source/modules/webaudio/AnalyserNode.idl b/third_party/WebKit/Source/modules/webaudio/AnalyserNode.idl
index a17621d..f066b8c 100644
--- a/third_party/WebKit/Source/modules/webaudio/AnalyserNode.idl
+++ b/third_party/WebKit/Source/modules/webaudio/AnalyserNode.idl
@@ -37,10 +37,10 @@
 
     // Copies the current frequency data into the passed array.
     // If the array has fewer elements than the frequencyBinCount, the excess elements will be dropped.
-    [LegacyInterfaceTypeChecking] void getFloatFrequencyData(Float32Array array);
-    [LegacyInterfaceTypeChecking] void getByteFrequencyData(Uint8Array array);
+    void getFloatFrequencyData(Float32Array array);
+    void getByteFrequencyData(Uint8Array array);
 
     // Real-time waveform data
-    [LegacyInterfaceTypeChecking] void getFloatTimeDomainData(Float32Array array);
-    [LegacyInterfaceTypeChecking] void getByteTimeDomainData(Uint8Array array);
+    void getFloatTimeDomainData(Float32Array array);
+    void getByteTimeDomainData(Uint8Array array);
 };
diff --git a/third_party/WebKit/Source/modules/webaudio/AudioParam.idl b/third_party/WebKit/Source/modules/webaudio/AudioParam.idl
index 6169def..cc3746f 100644
--- a/third_party/WebKit/Source/modules/webaudio/AudioParam.idl
+++ b/third_party/WebKit/Source/modules/webaudio/AudioParam.idl
@@ -43,7 +43,7 @@
 
     // Sets an array of arbitrary parameter values starting at time for the given duration.
     // The number of values will be scaled to fit into the desired duration.
-    [RaisesException, MeasureAs=AudioParamSetValueCurveAtTime, LegacyInterfaceTypeChecking] AudioParam setValueCurveAtTime(Float32Array values, double time, double duration);
+    [RaisesException, MeasureAs=AudioParamSetValueCurveAtTime] AudioParam setValueCurveAtTime(Float32Array values, double time, double duration);
 
     // Cancels all scheduled parameter changes with times greater than or equal to startTime.
     [RaisesException, MeasureAs=AudioParamCancelScheduledValues] AudioParam cancelScheduledValues(double startTime);
diff --git a/third_party/WebKit/Source/modules/webaudio/AudioParamTimeline.cpp b/third_party/WebKit/Source/modules/webaudio/AudioParamTimeline.cpp
index e16331e..f4967991 100644
--- a/third_party/WebKit/Source/modules/webaudio/AudioParamTimeline.cpp
+++ b/third_party/WebKit/Source/modules/webaudio/AudioParamTimeline.cpp
@@ -201,6 +201,7 @@
 void AudioParamTimeline::setValueCurveAtTime(DOMFloat32Array* curve, double time, double duration, ExceptionState& exceptionState)
 {
     ASSERT(isMainThread());
+    ASSERT(curve);
 
     if (!isNonNegativeAudioParamTime(time, exceptionState)
         || !isPositiveAudioParamTime(duration, exceptionState, "Duration"))
diff --git a/third_party/WebKit/Source/modules/webaudio/BiquadFilterNode.cpp b/third_party/WebKit/Source/modules/webaudio/BiquadFilterNode.cpp
index cd7ca03..412a92ab 100644
--- a/third_party/WebKit/Source/modules/webaudio/BiquadFilterNode.cpp
+++ b/third_party/WebKit/Source/modules/webaudio/BiquadFilterNode.cpp
@@ -110,8 +110,7 @@
 
 void BiquadFilterNode::getFrequencyResponse(const DOMFloat32Array* frequencyHz, DOMFloat32Array* magResponse, DOMFloat32Array* phaseResponse)
 {
-    if (!frequencyHz || !magResponse || !phaseResponse)
-        return;
+    ASSERT(frequencyHz && magResponse && phaseResponse);
 
     int n = std::min(frequencyHz->length(), std::min(magResponse->length(), phaseResponse->length()));
     if (n)
diff --git a/third_party/WebKit/Source/modules/webaudio/BiquadFilterNode.idl b/third_party/WebKit/Source/modules/webaudio/BiquadFilterNode.idl
index 9abd2b6..9783ab2a 100644
--- a/third_party/WebKit/Source/modules/webaudio/BiquadFilterNode.idl
+++ b/third_party/WebKit/Source/modules/webaudio/BiquadFilterNode.idl
@@ -43,7 +43,7 @@
     readonly attribute AudioParam Q; // Quality factor
     readonly attribute AudioParam gain; // in Decibels
 
-    [LegacyInterfaceTypeChecking] void getFrequencyResponse(Float32Array frequencyHz,
-                                                            Float32Array magResponse,
-                                                            Float32Array phaseResponse);
+    void getFrequencyResponse(Float32Array frequencyHz,
+                              Float32Array magResponse,
+                              Float32Array phaseResponse);
 };
diff --git a/third_party/WebKit/Source/modules/webaudio/ConvolverNode.idl b/third_party/WebKit/Source/modules/webaudio/ConvolverNode.idl
index 9f1a3fb0..6831fc32 100644
--- a/third_party/WebKit/Source/modules/webaudio/ConvolverNode.idl
+++ b/third_party/WebKit/Source/modules/webaudio/ConvolverNode.idl
@@ -26,6 +26,6 @@
 [
     Conditional=WEB_AUDIO
 ] interface ConvolverNode : AudioNode {
-    [RaisesException=Setter, LegacyInterfaceTypeChecking] attribute AudioBuffer buffer;
+    [RaisesException=Setter] attribute AudioBuffer? buffer;
     attribute boolean normalize;
 };
diff --git a/third_party/WebKit/Source/modules/webaudio/OscillatorNode.cpp b/third_party/WebKit/Source/modules/webaudio/OscillatorNode.cpp
index b62f824..ed38aa2 100644
--- a/third_party/WebKit/Source/modules/webaudio/OscillatorNode.cpp
+++ b/third_party/WebKit/Source/modules/webaudio/OscillatorNode.cpp
@@ -327,6 +327,7 @@
 void OscillatorHandler::setPeriodicWave(PeriodicWave* periodicWave)
 {
     ASSERT(isMainThread());
+    ASSERT(periodicWave);
 
     // This synchronizes with process().
     MutexLocker processLocker(m_processLock);
diff --git a/third_party/WebKit/Source/modules/webaudio/OscillatorNode.idl b/third_party/WebKit/Source/modules/webaudio/OscillatorNode.idl
index 8564d81..203abfe7 100644
--- a/third_party/WebKit/Source/modules/webaudio/OscillatorNode.idl
+++ b/third_party/WebKit/Source/modules/webaudio/OscillatorNode.idl
@@ -43,7 +43,7 @@
     [RaisesException] void start(optional double when);
     [RaisesException] void stop(optional double when);
 
-    [LegacyInterfaceTypeChecking] void setPeriodicWave(PeriodicWave periodicWave);
+    void setPeriodicWave(PeriodicWave periodicWave);
 
     attribute EventHandler onended;
 };
diff --git a/third_party/WebKit/Source/modules/webaudio/RealtimeAnalyser.cpp b/third_party/WebKit/Source/modules/webaudio/RealtimeAnalyser.cpp
index 26b2f68..6f8b620 100644
--- a/third_party/WebKit/Source/modules/webaudio/RealtimeAnalyser.cpp
+++ b/third_party/WebKit/Source/modules/webaudio/RealtimeAnalyser.cpp
@@ -190,9 +190,7 @@
 void RealtimeAnalyser::getFloatFrequencyData(DOMFloat32Array* destinationArray)
 {
     ASSERT(isMainThread());
-
-    if (!destinationArray)
-        return;
+    ASSERT(destinationArray);
 
     doFFTAnalysis();
 
@@ -215,9 +213,7 @@
 void RealtimeAnalyser::getByteFrequencyData(DOMUint8Array* destinationArray)
 {
     ASSERT(isMainThread());
-
-    if (!destinationArray)
-        return;
+    ASSERT(destinationArray);
 
     doFFTAnalysis();
 
@@ -252,9 +248,7 @@
 void RealtimeAnalyser::getFloatTimeDomainData(DOMFloat32Array* destinationArray)
 {
     ASSERT(isMainThread());
-
-    if (!destinationArray)
-        return;
+    ASSERT(destinationArray);
 
     unsigned fftSize = this->fftSize();
     size_t len = std::min(fftSize, destinationArray->length());
@@ -281,9 +275,7 @@
 void RealtimeAnalyser::getByteTimeDomainData(DOMUint8Array* destinationArray)
 {
     ASSERT(isMainThread());
-
-    if (!destinationArray)
-        return;
+    ASSERT(destinationArray);
 
     unsigned fftSize = this->fftSize();
     size_t len = std::min(fftSize, destinationArray->length());
diff --git a/third_party/WebKit/Source/modules/webaudio/ScriptProcessorNode.cpp b/third_party/WebKit/Source/modules/webaudio/ScriptProcessorNode.cpp
index 3108db80..ce9c88a 100644
--- a/third_party/WebKit/Source/modules/webaudio/ScriptProcessorNode.cpp
+++ b/third_party/WebKit/Source/modules/webaudio/ScriptProcessorNode.cpp
@@ -42,7 +42,6 @@
 ScriptProcessorHandler::ScriptProcessorHandler(AudioNode& node, float sampleRate, size_t bufferSize, unsigned numberOfInputChannels, unsigned numberOfOutputChannels)
     : AudioHandler(NodeTypeJavaScript, node, sampleRate)
     , m_doubleBufferIndex(0)
-    , m_doubleBufferIndexForEvent(0)
     , m_bufferSize(bufferSize)
     , m_bufferReadWriteIndex(0)
     , m_numberOfInputChannels(numberOfInputChannels)
@@ -166,26 +165,26 @@
             // The best we can do is clear out the buffer ourself here.
             outputBuffer->zero();
         } else if (context()->executionContext()) {
-            // Fire the event on the main thread, not this one (which is the realtime audio thread).
-            m_doubleBufferIndexForEvent = m_doubleBufferIndex;
-            context()->executionContext()->postTask(BLINK_FROM_HERE, createCrossThreadTask(&ScriptProcessorHandler::fireProcessEvent, PassRefPtr<ScriptProcessorHandler>(this)));
+            // Fire the event on the main thread with the appropriate buffer
+            // index.
+            context()->executionContext()->postTask(BLINK_FROM_HERE,
+                createCrossThreadTask(&ScriptProcessorHandler::fireProcessEvent, this, m_doubleBufferIndex));
         }
 
         swapBuffers();
     }
 }
 
-void ScriptProcessorHandler::fireProcessEvent()
+void ScriptProcessorHandler::fireProcessEvent(unsigned doubleBufferIndex)
 {
     ASSERT(isMainThread());
 
-    bool isIndexGood = m_doubleBufferIndexForEvent < 2;
-    ASSERT(isIndexGood);
-    if (!isIndexGood)
+    ASSERT(doubleBufferIndex < 2);
+    if (doubleBufferIndex > 1)
         return;
 
-    AudioBuffer* inputBuffer = m_inputBuffers[m_doubleBufferIndexForEvent].get();
-    AudioBuffer* outputBuffer = m_outputBuffers[m_doubleBufferIndexForEvent].get();
+    AudioBuffer* inputBuffer = m_inputBuffers[doubleBufferIndex].get();
+    AudioBuffer* outputBuffer = m_outputBuffers[doubleBufferIndex].get();
     ASSERT(outputBuffer);
     if (!outputBuffer)
         return;
diff --git a/third_party/WebKit/Source/modules/webaudio/ScriptProcessorNode.h b/third_party/WebKit/Source/modules/webaudio/ScriptProcessorNode.h
index 1b9bf9ae..dbb58cf 100644
--- a/third_party/WebKit/Source/modules/webaudio/ScriptProcessorNode.h
+++ b/third_party/WebKit/Source/modules/webaudio/ScriptProcessorNode.h
@@ -65,13 +65,13 @@
     double tailTime() const override;
     double latencyTime() const override;
 
-    void fireProcessEvent();
+    void fireProcessEvent(unsigned);
 
     // Double buffering
     unsigned doubleBufferIndex() const { return m_doubleBufferIndex; }
     void swapBuffers() { m_doubleBufferIndex = 1 - m_doubleBufferIndex; }
     unsigned m_doubleBufferIndex;
-    unsigned m_doubleBufferIndexForEvent;
+
     // These Persistent don't make reference cycles including the owner
     // ScriptProcessorNode.
     PersistentHeapVector<Member<AudioBuffer>> m_inputBuffers;
diff --git a/third_party/WebKit/Source/modules/webaudio/WaveShaperNode.idl b/third_party/WebKit/Source/modules/webaudio/WaveShaperNode.idl
index 586125a9..49ff1cc 100644
--- a/third_party/WebKit/Source/modules/webaudio/WaveShaperNode.idl
+++ b/third_party/WebKit/Source/modules/webaudio/WaveShaperNode.idl
@@ -31,6 +31,6 @@
 [
     Conditional=WEB_AUDIO
 ] interface WaveShaperNode : AudioNode {
-    [RaisesException=Setter, LegacyInterfaceTypeChecking] attribute Float32Array curve;
+    [RaisesException=Setter] attribute Float32Array? curve;
     attribute OverSampleType oversample;
 };
diff --git a/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.cpp b/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.cpp
index 2e298a3a..be4958b 100644
--- a/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.cpp
+++ b/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.cpp
@@ -2366,8 +2366,10 @@
         return String();
     }
     OwnPtr<GLchar[]> name = adoptArrayPtr(new GLchar[maxNameLength]);
-    GLsizei length;
+
+    GLsizei length = 0;
     webContext()->getActiveUniformBlockName(objectOrZero(program), uniformBlockIndex, maxNameLength, &length, name.get());
+
     return String(name.get(), length);
 }
 
@@ -3298,4 +3300,16 @@
     return GL_RGB;
 }
 
+const WebGLSamplerState* WebGL2RenderingContextBase::getTextureUnitSamplerState(GLenum target, GLuint unit) const
+{
+    ASSERT(unit < m_samplerUnits.size());
+
+    WebGLSampler* sampler = m_samplerUnits[unit];
+
+    if (sampler)
+        return sampler->getSamplerState();
+
+    return WebGLRenderingContextBase::getTextureUnitSamplerState(target, unit);
+}
+
 } // namespace blink
diff --git a/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.h b/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.h
index 47d94d2..ba0b485 100644
--- a/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.h
+++ b/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.h
@@ -229,6 +229,7 @@
     GLint getMaxTextureLevelForTarget(GLenum target) override;
     void renderbufferStorageImpl(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, const char* functionName) override;
     GLenum boundFramebufferColorFormat() override;
+    const WebGLSamplerState* getTextureUnitSamplerState(GLenum target, GLuint unit) const override;
 
     // Helper function to validate the target for compressedTex{Sub}Image3D.
     bool validateTexFunc3DTarget(const char* functionName, GLenum target);
diff --git a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp
index b0657c4..1dcf1f6e 100644
--- a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp
+++ b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp
@@ -34,6 +34,7 @@
 #include "core/dom/ExceptionCode.h"
 #include "core/dom/FlexibleArrayBufferView.h"
 #include "core/fetch/ImageResource.h"
+#include "core/frame/ImageBitmap.h"
 #include "core/frame/LocalFrame.h"
 #include "core/frame/Settings.h"
 #include "core/html/HTMLCanvasElement.h"
@@ -2046,6 +2047,33 @@
     return renderbuffer->emulatedStencilBuffer();
 }
 
+const WebGLSamplerState* WebGLRenderingContextBase::getTextureUnitSamplerState(GLenum target, GLuint unit) const
+{
+    ASSERT(unit < m_textureUnits.size());
+
+    WebGLTexture* texture = nullptr;
+
+    switch (target) {
+    case GL_TEXTURE_2D:
+        texture = m_textureUnits[unit].m_texture2DBinding;
+        break;
+    case GL_TEXTURE_CUBE_MAP:
+        texture = m_textureUnits[unit].m_textureCubeMapBinding;
+        break;
+    case GL_TEXTURE_2D_ARRAY:
+        texture = m_textureUnits[unit].m_texture2DArrayBinding;
+        break;
+    case GL_TEXTURE_3D:
+        texture = m_textureUnits[unit].m_texture3DBinding;
+        break;
+    }
+
+    if (texture)
+        return texture->getSamplerState();
+
+    return nullptr;
+}
+
 void WebGLRenderingContextBase::setBoundVertexArrayObject(ScriptState* scriptState, WebGLVertexArrayObjectBase* arrayObject)
 {
     if (arrayObject)
@@ -4312,6 +4340,10 @@
         synthesizeGLError(GL_INVALID_VALUE, "texImage2D", "no image data");
         return;
     }
+    if (pixels->data()->bufferBase()->isNeutered()) {
+        synthesizeGLError(GL_INVALID_VALUE, "texImage2D", "The source data has been neutered.");
+        return;
+    }
     if (isContextLost() || !validateTexFunc("texImage2D", NotTexSubImage2D, SourceImageData, target, level, internalformat, pixels->width(), pixels->height(), 0, format, type, 0, 0))
         return;
     if (type == GL_UNSIGNED_INT_10F_11F_11F_REV) {
@@ -4505,6 +4537,20 @@
     texImage2DImpl(target, level, internalformat, format, type, image.get(), WebGLImageConversion::HtmlDomVideo, m_unpackFlipY, m_unpackPremultiplyAlpha);
 }
 
+void WebGLRenderingContextBase::texImage2D(GLenum target, GLint level, GLenum internalformat,
+    GLenum format, GLenum type, PassRefPtrWillBeRawPtr<ImageBitmap> bitmap)
+{
+    ASSERT(bitmap->bitmapImage());
+    if (bitmap->isNeutered()) {
+        synthesizeGLError(GL_INVALID_VALUE, "texImage2D", "The source data has been neutered.");
+        return;
+    }
+    if (isContextLost() || !validateTexFunc("texImage2D", NotTexSubImage2D, SourceImageBitmap, target, level, 0, bitmap->width(), bitmap->height(), 0, format, type, 0, 0))
+        return;
+    StaticBitmapImage* imageForRender = bitmap->bitmapImage();
+    texImage2DImpl(target, level, internalformat, format, type, imageForRender, WebGLImageConversion::HtmlDomImage, m_unpackFlipY, m_unpackPremultiplyAlpha);
+}
+
 void WebGLRenderingContextBase::texParameter(GLenum target, GLenum pname, GLfloat paramf, GLint parami, bool isFloat)
 {
     if (isContextLost())
@@ -4633,6 +4679,10 @@
         synthesizeGLError(GL_INVALID_VALUE, "texSubImage2D", "no image data");
         return;
     }
+    if (pixels->data()->bufferBase()->isNeutered()) {
+        synthesizeGLError(GL_INVALID_VALUE, "texSubImage2D", "The source data has been neutered.");
+        return;
+    }
     if (isContextLost() || !validateTexFunc("texSubImage2D", TexSubImage2D, SourceImageData, target, level, 0,  pixels->width(), pixels->height(), 0, format, type, xoffset, yoffset))
         return;
     if (type == GL_UNSIGNED_INT_10F_11F_11F_REV) {
@@ -4713,6 +4763,20 @@
     texSubImage2DImpl(target, level, xoffset, yoffset, format, type, image.get(), WebGLImageConversion::HtmlDomVideo, m_unpackFlipY, m_unpackPremultiplyAlpha);
 }
 
+void WebGLRenderingContextBase::texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
+    GLenum format, GLenum type, PassRefPtrWillBeRawPtr<ImageBitmap> bitmap)
+{
+    ASSERT(bitmap->bitmapImage());
+    if (bitmap->isNeutered()) {
+        synthesizeGLError(GL_INVALID_VALUE, "texSubImage2D", "The source data has been neutered.");
+        return;
+    }
+    if (isContextLost() || !validateTexFunc("texSubImage2D", TexSubImage2D, SourceImageBitmap, target, level, 0, bitmap->width(), bitmap->height(), 0, format, type, 0, 0))
+        return;
+    StaticBitmapImage* imageForRender = bitmap->bitmapImage();
+    texSubImage2DImpl(target, level, xoffset, yoffset, format, type, imageForRender, WebGLImageConversion::HtmlDomImage, m_unpackFlipY, m_unpackPremultiplyAlpha);
+}
+
 void WebGLRenderingContextBase::uniform1f(const WebGLUniformLocation* location, GLfloat x)
 {
     if (isContextLost() || !location)
@@ -5392,8 +5456,10 @@
     WebGLTexture::TextureExtensionFlag flag = static_cast<WebGLTexture::TextureExtensionFlag>((extensionEnabled(OESTextureFloatLinearName) ? WebGLTexture::TextureFloatLinearExtensionEnabled : 0)
         | ((extensionEnabled(OESTextureHalfFloatLinearName) || isWebGL2OrHigher()) ? WebGLTexture::TextureHalfFloatLinearExtensionEnabled : 0));
     for (unsigned ii = 0; ii < m_onePlusMaxNonDefaultTextureUnit; ++ii) {
-        if ((m_textureUnits[ii].m_texture2DBinding.get() && m_textureUnits[ii].m_texture2DBinding->needToUseBlackTexture(flag))
-            || (m_textureUnits[ii].m_textureCubeMapBinding.get() && m_textureUnits[ii].m_textureCubeMapBinding->needToUseBlackTexture(flag))) {
+        const WebGLSamplerState* samplerState2D = getTextureUnitSamplerState(GL_TEXTURE_2D, ii);
+        const WebGLSamplerState* samplerStateCubeMap = getTextureUnitSamplerState(GL_TEXTURE_CUBE_MAP, ii);
+        if ((m_textureUnits[ii].m_texture2DBinding.get() && m_textureUnits[ii].m_texture2DBinding->needToUseBlackTexture(flag, samplerState2D))
+            || (m_textureUnits[ii].m_textureCubeMapBinding.get() && m_textureUnits[ii].m_textureCubeMapBinding->needToUseBlackTexture(flag, samplerStateCubeMap))) {
             if (ii != m_activeTextureUnit) {
                 webContext()->activeTexture(GL_TEXTURE0 + ii);
                 resetActiveUnit = true;
@@ -5414,9 +5480,9 @@
                 tex2D = m_textureUnits[ii].m_texture2DBinding.get();
                 texCubeMap = m_textureUnits[ii].m_textureCubeMapBinding.get();
             }
-            if (m_textureUnits[ii].m_texture2DBinding && m_textureUnits[ii].m_texture2DBinding->needToUseBlackTexture(flag))
+            if (m_textureUnits[ii].m_texture2DBinding && m_textureUnits[ii].m_texture2DBinding->needToUseBlackTexture(flag, samplerState2D))
                 webContext()->bindTexture(GL_TEXTURE_2D, objectOrZero(tex2D));
-            if (m_textureUnits[ii].m_textureCubeMapBinding && m_textureUnits[ii].m_textureCubeMapBinding->needToUseBlackTexture(flag))
+            if (m_textureUnits[ii].m_textureCubeMapBinding && m_textureUnits[ii].m_textureCubeMapBinding->needToUseBlackTexture(flag, samplerStateCubeMap))
                 webContext()->bindTexture(GL_TEXTURE_CUBE_MAP, objectOrZero(texCubeMap));
         }
     }
diff --git a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.h b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.h
index c2862a9..9527dd8 100644
--- a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.h
+++ b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.h
@@ -70,6 +70,7 @@
 class ExceptionState;
 class HTMLImageElement;
 class HTMLVideoElement;
+class ImageBitmap;
 class ImageBuffer;
 class ImageData;
 class IntSize;
@@ -301,6 +302,8 @@
         GLenum format, GLenum type, HTMLCanvasElement*, ExceptionState&);
     void texImage2D(GLenum target, GLint level, GLenum internalformat,
         GLenum format, GLenum type, HTMLVideoElement*, ExceptionState&);
+    void texImage2D(GLenum target, GLint level, GLenum internalformat,
+        GLenum format, GLenum type, PassRefPtrWillBeRawPtr<ImageBitmap>);
 
     void texParameterf(GLenum target, GLenum pname, GLfloat param);
     void texParameteri(GLenum target, GLenum pname, GLint param);
@@ -316,6 +319,8 @@
         GLenum format, GLenum type, HTMLCanvasElement*, ExceptionState&);
     void texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
         GLenum format, GLenum type, HTMLVideoElement*, ExceptionState&);
+    void texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
+        GLenum format, GLenum type, PassRefPtrWillBeRawPtr<ImageBitmap>);
 
     void uniform1f(const WebGLUniformLocation*, GLfloat x);
     void uniform1fv(const WebGLUniformLocation*, const FlexibleFloat32ArrayView&);
@@ -498,6 +503,8 @@
 
     WebGLRenderbuffer* ensureEmulatedStencilBuffer(GLenum target, WebGLRenderbuffer*);
 
+    virtual const WebGLSamplerState* getTextureUnitSamplerState(GLenum target, GLuint unit) const;
+
     // Structure for rendering to a DrawingBuffer, instead of directly
     // to the back-buffer of m_context.
     RefPtr<DrawingBuffer> m_drawingBuffer;
@@ -916,6 +923,7 @@
         SourceHTMLImageElement,
         SourceHTMLCanvasElement,
         SourceHTMLVideoElement,
+        SourceImageBitmap,
     };
 
     // Helper function for tex{Sub}Image2D to check if the input format/type/level/target/width/height/border/xoffset/yoffset are valid.
diff --git a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.idl b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.idl
index 77b4600..03df3622 100644
--- a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.idl
+++ b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.idl
@@ -631,6 +631,9 @@
     [RaisesException] void texImage2D(
         GLenum target, GLint level, GLenum internalformat,
         GLenum format, GLenum type, HTMLVideoElement video);
+    [RuntimeEnabled=ExperimentalCanvasFeatures] void texImage2D(
+        GLenum target, GLint level, GLenum internalformat,
+        GLenum format, GLenum type, ImageBitmap bitmap);
 
     void texSubImage2D(
         GLenum target, GLint level, GLint xoffset, GLint yoffset,
@@ -648,6 +651,9 @@
     [RaisesException] void texSubImage2D(
         GLenum target, GLint level, GLint xoffset, GLint yoffset,
         GLenum format, GLenum type, HTMLVideoElement video);
+    [RuntimeEnabled=ExperimentalCanvasFeatures] void texSubImage2D(
+        GLenum target, GLint level, GLint xoffset, GLint yoffset,
+        GLenum format, GLenum type, ImageBitmap bitmap);
 
     void uniform1f(WebGLUniformLocation? location, GLfloat x);
     void uniform1fv(WebGLUniformLocation? location, [FlexibleArrayBufferView] Float32Array v);
diff --git a/third_party/WebKit/Source/modules/webgl/WebGLSampler.cpp b/third_party/WebKit/Source/modules/webgl/WebGLSampler.cpp
index cc8958f..95688a0 100644
--- a/third_party/WebKit/Source/modules/webgl/WebGLSampler.cpp
+++ b/third_party/WebKit/Source/modules/webgl/WebGLSampler.cpp
@@ -10,6 +10,19 @@
 
 namespace blink {
 
+WebGLSamplerState::WebGLSamplerState()
+    : compreFunc(GL_LEQUAL)
+    , compreMode(GL_NONE)
+    , magFilter(GL_LINEAR)
+    , minFilter(GL_NEAREST_MIPMAP_LINEAR)
+    , wrapR(GL_REPEAT)
+    , wrapS(GL_REPEAT)
+    , wrapT(GL_REPEAT)
+    , maxLod(1000.0f)
+    , minLod(-1000.0f)
+{
+}
+
 WebGLSampler* WebGLSampler::create(WebGL2RenderingContextBase* ctx)
 {
     return new WebGLSampler(ctx);
@@ -23,15 +36,6 @@
 
 WebGLSampler::WebGLSampler(WebGL2RenderingContextBase* ctx)
     : WebGLSharedPlatform3DObject(ctx)
-    , m_compreFunc(GL_LEQUAL)
-    , m_compreMode(GL_NONE)
-    , m_magFilter(GL_LINEAR)
-    , m_minFilter(GL_NEAREST_MIPMAP_LINEAR)
-    , m_wrapR(GL_REPEAT)
-    , m_wrapS(GL_REPEAT)
-    , m_wrapT(GL_REPEAT)
-    , m_maxLod(1000.0f)
-    , m_minLod(-1000.0f)
 {
     setObject(ctx->webContext()->createSampler());
 }
@@ -55,25 +59,25 @@
             return;
         }
     case GL_TEXTURE_COMPARE_FUNC:
-        m_compreFunc = param;
+        m_state.compreFunc = param;
         break;
     case GL_TEXTURE_COMPARE_MODE:
-        m_compreMode = param;
+        m_state.compreMode = param;
         break;
     case GL_TEXTURE_MAG_FILTER:
-        m_magFilter = param;
+        m_state.magFilter = param;
         break;
     case GL_TEXTURE_MIN_FILTER:
-        m_minFilter = param;
+        m_state.minFilter = param;
         break;
     case GL_TEXTURE_WRAP_R:
-        m_wrapR = param;
+        m_state.wrapR = param;
         break;
     case GL_TEXTURE_WRAP_S:
-        m_wrapS = param;
+        m_state.wrapS = param;
         break;
     case GL_TEXTURE_WRAP_T:
-        m_wrapT = param;
+        m_state.wrapT = param;
         break;
     default:
         ASSERT_NOT_REACHED();
@@ -99,10 +103,10 @@
             return;
         }
     case GL_TEXTURE_MAX_LOD:
-        m_maxLod = param;
+        m_state.maxLod = param;
         break;
     case GL_TEXTURE_MIN_LOD:
-        m_minLod = param;
+        m_state.minLod = param;
         break;
     default:
         ASSERT_NOT_REACHED();
diff --git a/third_party/WebKit/Source/modules/webgl/WebGLSampler.h b/third_party/WebKit/Source/modules/webgl/WebGLSampler.h
index 7a5f1792..167549b 100644
--- a/third_party/WebKit/Source/modules/webgl/WebGLSampler.h
+++ b/third_party/WebKit/Source/modules/webgl/WebGLSampler.h
@@ -6,6 +6,7 @@
 #define WebGLSampler_h
 
 #include "modules/webgl/WebGLSharedPlatform3DObject.h"
+#include "modules/webgl/WebGLTexture.h"
 
 namespace blink {
 
@@ -20,15 +21,17 @@
 
     void setParameteri(GLenum pname, GLint param);
     void setParameterf(GLenum pname, GLfloat param);
-    GLenum getCompareFunc() const { return m_compreFunc; }
-    GLenum getCompareMode() const { return m_compreMode; }
-    GLenum getMagFilter() const { return m_magFilter; }
-    GLenum getMinFilter() const { return m_minFilter; }
-    GLenum getWrapR() const { return m_wrapR; }
-    GLenum getWrapS() const { return m_wrapS; }
-    GLenum getWrapT() const { return m_wrapT; }
-    GLfloat getMaxLod() const { return m_maxLod; }
-    GLfloat getMinLod() const { return m_minLod; }
+    GLenum getCompareFunc() const { return m_state.compreFunc; }
+    GLenum getCompareMode() const { return m_state.compreMode; }
+    GLenum getMagFilter() const { return m_state.magFilter; }
+    GLenum getMinFilter() const { return m_state.minFilter; }
+    GLenum getWrapR() const { return m_state.wrapR; }
+    GLenum getWrapS() const { return m_state.wrapS; }
+    GLenum getWrapT() const { return m_state.wrapT; }
+    GLfloat getMaxLod() const { return m_state.maxLod; }
+    GLfloat getMinLod() const { return m_state.minLod; }
+
+    const WebGLSamplerState* getSamplerState() const { return &m_state; }
 
 protected:
     explicit WebGLSampler(WebGL2RenderingContextBase*);
@@ -38,15 +41,7 @@
 private:
     bool isSampler() const override { return true; }
 
-    GLenum m_compreFunc;
-    GLenum m_compreMode;
-    GLenum m_magFilter;
-    GLenum m_minFilter;
-    GLenum m_wrapR;
-    GLenum m_wrapS;
-    GLenum m_wrapT;
-    GLfloat m_maxLod;
-    GLfloat m_minLod;
+    WebGLSamplerState m_state;
 };
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/modules/webgl/WebGLTexture.cpp b/third_party/WebKit/Source/modules/webgl/WebGLTexture.cpp
index 80d5bd1..3b497766 100644
--- a/third_party/WebKit/Source/modules/webgl/WebGLTexture.cpp
+++ b/third_party/WebKit/Source/modules/webgl/WebGLTexture.cpp
@@ -39,11 +39,6 @@
 WebGLTexture::WebGLTexture(WebGLRenderingContextBase* ctx)
     : WebGLSharedPlatform3DObject(ctx)
     , m_target(0)
-    , m_minFilter(GL_NEAREST_MIPMAP_LINEAR)
-    , m_magFilter(GL_LINEAR)
-    , m_wrapR(GL_REPEAT)
-    , m_wrapS(GL_REPEAT)
-    , m_wrapT(GL_REPEAT)
     , m_isNPOT(false)
     , m_isCubeComplete(false)
     , m_isComplete(false)
@@ -101,7 +96,7 @@
         case GL_LINEAR_MIPMAP_NEAREST:
         case GL_NEAREST_MIPMAP_LINEAR:
         case GL_LINEAR_MIPMAP_LINEAR:
-            m_minFilter = param;
+            m_samplerState.minFilter = param;
             break;
         }
         break;
@@ -109,7 +104,7 @@
         switch (param) {
         case GL_NEAREST:
         case GL_LINEAR:
-            m_magFilter = param;
+            m_samplerState.magFilter = param;
             break;
         }
         break;
@@ -118,7 +113,7 @@
         case GL_CLAMP_TO_EDGE:
         case GL_MIRRORED_REPEAT:
         case GL_REPEAT:
-            m_wrapR = param;
+            m_samplerState.wrapR = param;
             break;
         }
         break;
@@ -127,7 +122,7 @@
         case GL_CLAMP_TO_EDGE:
         case GL_MIRRORED_REPEAT:
         case GL_REPEAT:
-            m_wrapS = param;
+            m_samplerState.wrapS = param;
             break;
         }
         break;
@@ -136,7 +131,7 @@
         case GL_CLAMP_TO_EDGE:
         case GL_MIRRORED_REPEAT:
         case GL_REPEAT:
-            m_wrapT = param;
+            m_samplerState.wrapT = param;
             break;
         }
         break;
@@ -303,14 +298,15 @@
     return m_isNPOT;
 }
 
-bool WebGLTexture::needToUseBlackTexture(TextureExtensionFlag flag) const
+bool WebGLTexture::needToUseBlackTexture(TextureExtensionFlag flag, const WebGLSamplerState* samplerState) const
 {
+    ASSERT(samplerState);
     if (!object())
         return false;
     if (m_needToUseBlackTexture)
         return true;
     if ((m_isFloatType && !(flag & TextureFloatLinearExtensionEnabled)) || (m_isHalfFloatType && !(flag && TextureHalfFloatLinearExtensionEnabled))) {
-        if (m_magFilter != GL_NEAREST || (m_minFilter != GL_NEAREST && m_minFilter != GL_NEAREST_MIPMAP_NEAREST))
+        if (samplerState->magFilter != GL_NEAREST || (samplerState->minFilter != GL_NEAREST && samplerState->minFilter != GL_NEAREST_MIPMAP_NEAREST))
             return true;
     }
     return false;
@@ -445,16 +441,19 @@
     m_isHalfFloatType = m_info[0][0].type == GL_HALF_FLOAT_OES;
 
     m_needToUseBlackTexture = false;
-    // NPOT
-    if (!m_isWebGL2OrHigher && m_isNPOT && ((m_minFilter != GL_NEAREST && m_minFilter != GL_LINEAR)
-        || m_wrapS != GL_CLAMP_TO_EDGE || m_wrapT != GL_CLAMP_TO_EDGE || (m_target == GL_TEXTURE_3D && m_wrapR != GL_CLAMP_TO_EDGE)))
-        m_needToUseBlackTexture = true;
     // If it is a Cube texture, check Cube Completeness first
     if (m_info.size() > 1 && !m_isCubeComplete)
         m_needToUseBlackTexture = true;
-    // Completeness
-    if (!m_isComplete && m_minFilter != GL_NEAREST && m_minFilter != GL_LINEAR)
-        m_needToUseBlackTexture = true;
+    if (!m_isWebGL2OrHigher) {
+        // We can do these checks up front in WebGL 1 because there's no separate samplers.
+        // NPOT
+        if (m_isNPOT && ((m_samplerState.minFilter != GL_NEAREST && m_samplerState.minFilter != GL_LINEAR)
+            || m_samplerState.wrapS != GL_CLAMP_TO_EDGE || m_samplerState.wrapT != GL_CLAMP_TO_EDGE))
+            m_needToUseBlackTexture = true;
+        // Completeness
+        if (!m_isComplete && m_samplerState.minFilter != GL_NEAREST && m_samplerState.minFilter != GL_LINEAR)
+            m_needToUseBlackTexture = true;
+    }
 }
 
 const WebGLTexture::LevelInfo* WebGLTexture::getLevelInfo(GLenum target, GLint level) const
diff --git a/third_party/WebKit/Source/modules/webgl/WebGLTexture.h b/third_party/WebKit/Source/modules/webgl/WebGLTexture.h
index 8c0b749f..b1fbaf26 100644
--- a/third_party/WebKit/Source/modules/webgl/WebGLTexture.h
+++ b/third_party/WebKit/Source/modules/webgl/WebGLTexture.h
@@ -31,6 +31,20 @@
 
 namespace blink {
 
+struct WebGLSamplerState {
+    WebGLSamplerState();
+
+    GLenum compreFunc;
+    GLenum compreMode;
+    GLenum magFilter;
+    GLenum minFilter;
+    GLenum wrapR;
+    GLenum wrapS;
+    GLenum wrapT;
+    GLfloat maxLod;
+    GLfloat minLod;
+};
+
 class WebGLTexture final : public WebGLSharedPlatform3DObject {
     DEFINE_WRAPPERTYPEINFO();
 public:
@@ -49,7 +63,7 @@
 
     GLenum getTarget() const { return m_target; }
 
-    int getMinFilter() const { return m_minFilter; }
+    int getMinFilter() const { return m_samplerState.minFilter; }
 
     void setLevelInfo(GLenum target, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLenum type);
     void setTexStorageInfo(GLenum target, GLint levels, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth);
@@ -75,13 +89,15 @@
 
     bool isNPOT() const;
     // Determine if texture sampling should always return [0, 0, 0, 1] (OpenGL ES 2.0 Sec 3.8.2).
-    bool needToUseBlackTexture(TextureExtensionFlag) const;
+    bool needToUseBlackTexture(TextureExtensionFlag, const WebGLSamplerState*) const;
 
     bool hasEverBeenBound() const { return object() && m_target; }
 
     static GLint computeLevelCount(GLsizei width, GLsizei height, GLsizei depth);
     static GLenum getValidTypeForInternalFormat(GLenum);
 
+    const WebGLSamplerState* getSamplerState() const { return &m_samplerState; }
+
 private:
     explicit WebGLTexture(WebGLRenderingContextBase*);
 
@@ -127,11 +143,7 @@
 
     GLenum m_target;
 
-    GLenum m_minFilter;
-    GLenum m_magFilter;
-    GLenum m_wrapR;
-    GLenum m_wrapS;
-    GLenum m_wrapT;
+    WebGLSamplerState m_samplerState;
 
     Vector<Vector<LevelInfo>> m_info;
 
diff --git a/third_party/WebKit/Source/platform/BUILD.gn b/third_party/WebKit/Source/platform/BUILD.gn
index c59f6534..1242951 100644
--- a/third_party/WebKit/Source/platform/BUILD.gn
+++ b/third_party/WebKit/Source/platform/BUILD.gn
@@ -201,6 +201,7 @@
     "//gpu/command_buffer/client:gles2_c_lib",
     "//skia",
     "//third_party:jpeg",
+    "//third_party/WebKit/Source/wtf",
     "//third_party/iccjpeg",
     "//third_party/libpng",
     "//third_party/libwebp",
@@ -212,7 +213,6 @@
   deps = [
     ":make_platform_generated",
     "//third_party/WebKit/Source/platform/heap",
-    "//third_party/WebKit/Source/wtf",
     "//third_party/harfbuzz-ng",
     "//third_party/icu",
     "//ui/gfx/geometry",
diff --git a/third_party/WebKit/Source/platform/MemoryPurgeController.cpp b/third_party/WebKit/Source/platform/MemoryPurgeController.cpp
index d00d9cc..3860e7e7 100644
--- a/third_party/WebKit/Source/platform/MemoryPurgeController.cpp
+++ b/third_party/WebKit/Source/platform/MemoryPurgeController.cpp
@@ -9,13 +9,6 @@
 #include "public/platform/Platform.h"
 #include "wtf/Partitions.h"
 
-namespace {
-
-// TODO(bashi): Determine appropriate value for this interval.
-const size_t kInactiveTimerIntervalInSecond = 10;
-
-} // namespace
-
 namespace blink {
 
 DEFINE_TRACE(MemoryPurgeClient)
@@ -24,7 +17,6 @@
 
 MemoryPurgeController::MemoryPurgeController()
     : m_deviceKind(Platform::current()->isLowEndDeviceMode() ? DeviceKind::LowEnd : DeviceKind::NotSpecified)
-    , m_inactiveTimer(this, &MemoryPurgeController::pageInactiveTask)
 {
 }
 
@@ -32,37 +24,12 @@
 {
 }
 
-void MemoryPurgeController::pageBecameActive()
+void MemoryPurgeController::purgeMemory()
 {
-    m_inactiveTimer.stop();
-}
-
-void MemoryPurgeController::pageBecameInactive()
-{
-    if (!m_inactiveTimer.isActive())
-        m_inactiveTimer.startOneShot(kInactiveTimerIntervalInSecond, BLINK_FROM_HERE);
-}
-
-void MemoryPurgeController::pageInactiveTask(Timer<MemoryPurgeController>*)
-{
-    static const size_t maxSizeInKB = 10 * 1024;
-
-    size_t totalSizeBefore = WTF::Partitions::totalSizeOfCommittedPages();
-    purgeMemory(MemoryPurgeMode::InactiveTab);
-    size_t totalSizeAfter = WTF::Partitions::totalSizeOfCommittedPages();
-    if (totalSizeAfter >= totalSizeBefore)
-        return;
-    size_t reclaimedInKB = (totalSizeBefore - totalSizeAfter) / 1024 + 1;
-    if (reclaimedInKB >= maxSizeInKB)
-        reclaimedInKB = maxSizeInKB - 1;
-    Platform::current()->histogramCustomCounts("MemoryPurgeController.ReclaimedPartitionAllocInactiveTab", reclaimedInKB, 1, maxSizeInKB, 50);
-}
-
-void MemoryPurgeController::purgeMemory(MemoryPurgeMode purgeMode)
-{
+    // TODO(bashi): Add UMA
     TRACE_EVENT0("blink", "MemoryPurgeController::purgeMemory");
     for (auto& client : m_clients)
-        client->purgeMemory(purgeMode, m_deviceKind);
+        client->purgeMemory(m_deviceKind);
     WTF::Partitions::decommitFreeableMemory();
 }
 
diff --git a/third_party/WebKit/Source/platform/MemoryPurgeController.h b/third_party/WebKit/Source/platform/MemoryPurgeController.h
index 9d10d8f2..59114b19 100644
--- a/third_party/WebKit/Source/platform/MemoryPurgeController.h
+++ b/third_party/WebKit/Source/platform/MemoryPurgeController.h
@@ -12,12 +12,6 @@
 
 namespace blink {
 
-enum class MemoryPurgeMode {
-    // The tab contains the webview went to background
-    InactiveTab,
-    // TODO(bashi): Add more modes as needed.
-};
-
 enum class DeviceKind {
     NotSpecified,
     LowEnd,
@@ -33,7 +27,7 @@
 
     // MemoryPurgeController invokes this callback when a memory purge event
     // has occurred.
-    virtual void purgeMemory(MemoryPurgeMode, DeviceKind) = 0;
+    virtual void purgeMemory(DeviceKind) = 0;
 
     DECLARE_VIRTUAL_TRACE();
 };
@@ -44,6 +38,8 @@
 // Page.
 class PLATFORM_EXPORT MemoryPurgeController final : public NoBaseWillBeGarbageCollectedFinalized<MemoryPurgeController> {
 public:
+    static void onMemoryPressure();
+
     static PassOwnPtrWillBeRawPtr<MemoryPurgeController> create()
     {
         return adoptPtrWillBeNoop(new MemoryPurgeController);
@@ -66,20 +62,15 @@
         m_clients.remove(client);
     }
 
-    void pageBecameActive();
-    void pageBecameInactive();
-    void pageInactiveTask(Timer<MemoryPurgeController>*);
+    void purgeMemory();
 
     DECLARE_TRACE();
 
 private:
     MemoryPurgeController();
 
-    void purgeMemory(MemoryPurgeMode);
-
     WillBeHeapHashSet<RawPtrWillBeWeakMember<MemoryPurgeClient>> m_clients;
     DeviceKind m_deviceKind;
-    Timer<MemoryPurgeController> m_inactiveTimer;
 };
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in b/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in
index 491578c9..3cf385c 100644
--- a/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in
+++ b/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in
@@ -44,6 +44,7 @@
 CSSAttributeCaseSensitivity status=experimental
 CSSBackdropFilter status=experimental
 CSSCompositing status=stable
+CSSContainment status=experimental
 CSSFontDisplay status=experimental
 CSSFontSizeAdjust status=experimental
 CSSGridLayout status=experimental
@@ -137,8 +138,7 @@
 PresentationReceiver status=test
 PromiseRejectionEvent status=stable
 PushMessaging status=stable
-// Push messaging payloads are blocked on the Push API supporting encryption.
-PushMessagingData status=test
+PushMessagingData status=experimental
 QuotaPromise status=experimental
 ReducedReferrerGranularity
 RenderingPipelineThrottling status=experimental
diff --git a/third_party/WebKit/Source/platform/blink_platform.gypi b/third_party/WebKit/Source/platform/blink_platform.gypi
index f0dbfe7..5d374e0 100644
--- a/third_party/WebKit/Source/platform/blink_platform.gypi
+++ b/third_party/WebKit/Source/platform/blink_platform.gypi
@@ -1072,6 +1072,8 @@
       'testing/UnitTestHelpers.h',
     ],
     'platform_test_support_files': [
+      'graphics/test/FakeGraphicsLayerFactory.cpp',
+      'graphics/test/FakeGraphicsLayerFactory.h',
       'testing/GeometryPrinters.cpp',
       'testing/GeometryPrinters.h',
       'testing/PaintPrinters.cpp',
diff --git a/third_party/WebKit/Source/platform/blink_platform_tests.gyp b/third_party/WebKit/Source/platform/blink_platform_tests.gyp
index 0eef2e6..5305eeb 100644
--- a/third_party/WebKit/Source/platform/blink_platform_tests.gyp
+++ b/third_party/WebKit/Source/platform/blink_platform_tests.gyp
@@ -120,11 +120,15 @@
       'type': 'static_library',
       'dependencies': [
         '../config.gyp:config',
+        '../wtf/wtf.gyp:wtf',
         'blink_platform.gyp:blink_platform',
       ],
       'defines': [
         'INSIDE_BLINK',
       ],
+      'include_dirs': [
+        '<(SHARED_INTERMEDIATE_DIR)/blink',
+      ],
       'sources': [
         '<@(platform_test_support_files)',
       ],
diff --git a/third_party/WebKit/Source/platform/exported/WebMediaConstraints.cpp b/third_party/WebKit/Source/platform/exported/WebMediaConstraints.cpp
index 6e617b5c..96f5e381 100644
--- a/third_party/WebKit/Source/platform/exported/WebMediaConstraints.cpp
+++ b/third_party/WebKit/Source/platform/exported/WebMediaConstraints.cpp
@@ -42,6 +42,7 @@
     static PassRefPtr<WebMediaConstraintsPrivate> create();
     static PassRefPtr<WebMediaConstraintsPrivate> create(const WebVector<WebMediaConstraint>& optional, const WebVector<WebMediaConstraint>& mandatory);
 
+    bool isEmpty() const;
     void getOptionalConstraints(WebVector<WebMediaConstraint>&);
     void getMandatoryConstraints(WebVector<WebMediaConstraint>&);
     bool getMandatoryConstraintValue(const WebString& name, WebString& value);
@@ -72,6 +73,11 @@
 {
 }
 
+bool WebMediaConstraintsPrivate::isEmpty() const
+{
+    return m_optional.isEmpty() && m_mandatory.isEmpty();
+}
+
 void WebMediaConstraintsPrivate::getOptionalConstraints(WebVector<WebMediaConstraint>& constraints)
 {
     constraints = m_optional;
@@ -116,6 +122,11 @@
     m_private.reset();
 }
 
+bool WebMediaConstraints::isEmpty() const
+{
+    return m_private.isNull() || m_private->isEmpty();
+}
+
 void WebMediaConstraints::getMandatoryConstraints(WebVector<WebMediaConstraint>& constraints) const
 {
     ASSERT(!isNull());
diff --git a/third_party/WebKit/Source/platform/graphics/test/FakeGraphicsLayerFactory.cpp b/third_party/WebKit/Source/platform/graphics/test/FakeGraphicsLayerFactory.cpp
new file mode 100644
index 0000000..5039db3
--- /dev/null
+++ b/third_party/WebKit/Source/platform/graphics/test/FakeGraphicsLayerFactory.cpp
@@ -0,0 +1,30 @@
+// 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.
+
+#include "config.h"
+#include "platform/graphics/test/FakeGraphicsLayerFactory.h"
+
+#include "platform/graphics/GraphicsLayer.h"
+#include "wtf/PassOwnPtr.h"
+#include "wtf/StdLibExtras.h"
+
+namespace blink {
+
+FakeGraphicsLayerFactory::FakeGraphicsLayerFactory()
+{
+}
+
+// static
+FakeGraphicsLayerFactory* FakeGraphicsLayerFactory::instance()
+{
+    DEFINE_STATIC_LOCAL(FakeGraphicsLayerFactory, factory, ());
+    return &factory;
+}
+
+PassOwnPtr<GraphicsLayer> FakeGraphicsLayerFactory::createGraphicsLayer(GraphicsLayerClient* client)
+{
+    return adoptPtr(new GraphicsLayer(client));
+}
+
+} // namespace blink
diff --git a/third_party/WebKit/Source/platform/graphics/test/FakeGraphicsLayerFactory.h b/third_party/WebKit/Source/platform/graphics/test/FakeGraphicsLayerFactory.h
new file mode 100644
index 0000000..4cf0463
--- /dev/null
+++ b/third_party/WebKit/Source/platform/graphics/test/FakeGraphicsLayerFactory.h
@@ -0,0 +1,25 @@
+// 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.
+
+#ifndef FakeGraphicsLayerFactory_h
+#define FakeGraphicsLayerFactory_h
+
+#include "platform/graphics/GraphicsLayerFactory.h"
+
+namespace blink {
+
+class FakeGraphicsLayerFactory : public GraphicsLayerFactory {
+public:
+    static FakeGraphicsLayerFactory* instance();
+
+    // GraphicsLayerFactory
+    PassOwnPtr<GraphicsLayer> createGraphicsLayer(GraphicsLayerClient*) override;
+
+private:
+    FakeGraphicsLayerFactory();
+};
+
+} // namespace blink
+
+#endif // FakeGraphicsLayerFactory_h
diff --git a/third_party/WebKit/Source/platform/mac/ScrollAnimatorMac.h b/third_party/WebKit/Source/platform/mac/ScrollAnimatorMac.h
index e324f1b..b8665e48 100644
--- a/third_party/WebKit/Source/platform/mac/ScrollAnimatorMac.h
+++ b/third_party/WebKit/Source/platform/mac/ScrollAnimatorMac.h
@@ -30,6 +30,7 @@
 #include "platform/geometry/FloatPoint.h"
 #include "platform/geometry/FloatSize.h"
 #include "platform/geometry/IntRect.h"
+#include "platform/heap/Handle.h"
 #include "platform/scroll/ScrollAnimatorBase.h"
 #include "wtf/RetainPtr.h"
 
@@ -44,11 +45,13 @@
 class Scrollbar;
 
 class PLATFORM_EXPORT ScrollAnimatorMac : public ScrollAnimatorBase {
-
+    WILL_BE_USING_PRE_FINALIZER(ScrollAnimatorMac, dispose);
 public:
     ScrollAnimatorMac(ScrollableArea*);
     ~ScrollAnimatorMac() override;
 
+    void dispose() override;
+
     void immediateScrollToPointForScrollAnimation(const FloatPoint& newPosition);
     bool haveScrolledSincePageLoad() const { return m_haveScrolledSincePageLoad; }
 
@@ -64,6 +67,11 @@
 
     static bool canUseCoordinatedScrollbar();
 
+    DEFINE_INLINE_VIRTUAL_TRACE()
+    {
+        ScrollAnimatorBase::trace(visitor);
+    }
+
 private:
     RetainPtr<id> m_scrollAnimationHelper;
     RetainPtr<WebScrollAnimationHelperDelegate> m_scrollAnimationHelperDelegate;
diff --git a/third_party/WebKit/Source/platform/mac/ScrollAnimatorMac.mm b/third_party/WebKit/Source/platform/mac/ScrollAnimatorMac.mm
index af0ba67..fb411cf 100644
--- a/third_party/WebKit/Source/platform/mac/ScrollAnimatorMac.mm
+++ b/third_party/WebKit/Source/platform/mac/ScrollAnimatorMac.mm
@@ -679,9 +679,9 @@
 
 namespace blink {
 
-PassOwnPtr<ScrollAnimatorBase> ScrollAnimatorBase::create(ScrollableArea* scrollableArea)
+PassOwnPtrWillBeRawPtr<ScrollAnimatorBase> ScrollAnimatorBase::create(ScrollableArea* scrollableArea)
 {
-    return adoptPtr(new ScrollAnimatorMac(scrollableArea));
+    return adoptPtrWillBeNoop(new ScrollAnimatorMac(scrollableArea));
 }
 
 ScrollAnimatorMac::ScrollAnimatorMac(ScrollableArea* scrollableArea)
@@ -691,6 +691,10 @@
     , m_haveScrolledSincePageLoad(false)
     , m_needsScrollerStyleUpdate(false)
 {
+#if ENABLE(OILPAN)
+    ThreadState::current()->registerPreFinalizer(this);
+#endif
+
     m_scrollAnimationHelperDelegate.adoptNS([[WebScrollAnimationHelperDelegate alloc] initWithScrollAnimator:this]);
     m_scrollAnimationHelper.adoptNS([[NSClassFromString(@"NSScrollAnimationHelper") alloc] initWithDelegate:m_scrollAnimationHelperDelegate.get()]);
 
@@ -704,6 +708,13 @@
 
 ScrollAnimatorMac::~ScrollAnimatorMac()
 {
+#if !ENABLE(OILPAN)
+    dispose();
+#endif
+}
+
+void ScrollAnimatorMac::dispose()
+{
     if (ScrollbarThemeMacCommon::isOverlayAPIAvailable()) {
         BEGIN_BLOCK_OBJC_EXCEPTIONS;
         [m_scrollbarPainterControllerDelegate.get() invalidate];
@@ -713,6 +724,8 @@
         [m_scrollAnimationHelperDelegate.get() invalidate];
         END_BLOCK_OBJC_EXCEPTIONS;
     }
+    m_initialScrollbarPaintTimer.stop();
+    m_sendContentAreaScrolledTimer.stop();
 }
 
 ScrollResultOneDimensional ScrollAnimatorMac::userScroll(ScrollbarOrientation orientation, ScrollGranularity granularity, float step, float delta)
diff --git a/third_party/WebKit/Source/platform/scroll/ProgrammaticScrollAnimator.cpp b/third_party/WebKit/Source/platform/scroll/ProgrammaticScrollAnimator.cpp
index 4e4099a..2b807d0 100644
--- a/third_party/WebKit/Source/platform/scroll/ProgrammaticScrollAnimator.cpp
+++ b/third_party/WebKit/Source/platform/scroll/ProgrammaticScrollAnimator.cpp
@@ -18,9 +18,9 @@
 
 namespace blink {
 
-PassOwnPtr<ProgrammaticScrollAnimator> ProgrammaticScrollAnimator::create(ScrollableArea* scrollableArea)
+PassOwnPtrWillBeRawPtr<ProgrammaticScrollAnimator> ProgrammaticScrollAnimator::create(ScrollableArea* scrollableArea)
 {
-    return adoptPtr(new ProgrammaticScrollAnimator(scrollableArea));
+    return adoptPtrWillBeNoop(new ProgrammaticScrollAnimator(scrollableArea));
 }
 
 ProgrammaticScrollAnimator::ProgrammaticScrollAnimator(ScrollableArea* scrollableArea)
@@ -289,4 +289,9 @@
     return m_compositorPlayer.get();
 }
 
+DEFINE_TRACE(ProgrammaticScrollAnimator)
+{
+    visitor->trace(m_scrollableArea);
+}
+
 } // namespace blink
diff --git a/third_party/WebKit/Source/platform/scroll/ProgrammaticScrollAnimator.h b/third_party/WebKit/Source/platform/scroll/ProgrammaticScrollAnimator.h
index ef6286a..d45cd66 100644
--- a/third_party/WebKit/Source/platform/scroll/ProgrammaticScrollAnimator.h
+++ b/third_party/WebKit/Source/platform/scroll/ProgrammaticScrollAnimator.h
@@ -23,13 +23,13 @@
 
 // Animator for fixed-destination scrolls, such as those triggered by
 // CSSOM View scroll APIs.
-class ProgrammaticScrollAnimator : private WebCompositorAnimationPlayerClient, WebCompositorAnimationDelegate {
+class ProgrammaticScrollAnimator : public NoBaseWillBeGarbageCollectedFinalized<ProgrammaticScrollAnimator>, private WebCompositorAnimationPlayerClient, WebCompositorAnimationDelegate {
     WTF_MAKE_NONCOPYABLE(ProgrammaticScrollAnimator);
-    USING_FAST_MALLOC(ProgrammaticScrollAnimator);
+    USING_FAST_MALLOC_WILL_BE_REMOVED(ProgrammaticScrollAnimator);
 public:
-    static PassOwnPtr<ProgrammaticScrollAnimator> create(ScrollableArea*);
+    static PassOwnPtrWillBeRawPtr<ProgrammaticScrollAnimator> create(ScrollableArea*);
 
-    ~ProgrammaticScrollAnimator();
+    virtual ~ProgrammaticScrollAnimator();
 
     void scrollToOffsetWithoutAnimation(const FloatPoint&);
     void animateToOffset(FloatPoint);
@@ -46,6 +46,8 @@
     // WebCompositorAnimationPlayerClient implementation.
     WebCompositorAnimationPlayer* compositorPlayer() const override;
 
+    DECLARE_TRACE();
+
 private:
     explicit ProgrammaticScrollAnimator(ScrollableArea*);
 
@@ -76,8 +78,7 @@
     OwnPtr<WebCompositorAnimationPlayer> m_compositorPlayer;
     int m_compositorAnimationAttachedToLayerId;
 
-    GC_PLUGIN_IGNORE("509911")
-    ScrollableArea* m_scrollableArea;
+    RawPtrWillBeMember<ScrollableArea> m_scrollableArea;
     OwnPtr<WebScrollOffsetAnimationCurve> m_animationCurve;
     FloatPoint m_targetOffset;
     double m_startTime;
diff --git a/third_party/WebKit/Source/platform/scroll/ScrollAnimator.cpp b/third_party/WebKit/Source/platform/scroll/ScrollAnimator.cpp
index a01daa2..a6dc9bff 100644
--- a/third_party/WebKit/Source/platform/scroll/ScrollAnimator.cpp
+++ b/third_party/WebKit/Source/platform/scroll/ScrollAnimator.cpp
@@ -41,11 +41,11 @@
 
 namespace blink {
 
-PassOwnPtr<ScrollAnimatorBase> ScrollAnimatorBase::create(ScrollableArea* scrollableArea)
+PassOwnPtrWillBeRawPtr<ScrollAnimatorBase> ScrollAnimatorBase::create(ScrollableArea* scrollableArea)
 {
     if (scrollableArea && scrollableArea->scrollAnimatorEnabled())
-        return adoptPtr(new ScrollAnimator(scrollableArea));
-    return adoptPtr(new ScrollAnimatorBase(scrollableArea));
+        return adoptPtrWillBeNoop(new ScrollAnimator(scrollableArea));
+    return adoptPtrWillBeNoop(new ScrollAnimatorBase(scrollableArea));
 }
 
 ScrollAnimator::ScrollAnimator(ScrollableArea* scrollableArea, WTF::TimeFunction timeFunction)
@@ -150,4 +150,9 @@
     notifyPositionChanged();
 }
 
+DEFINE_TRACE(ScrollAnimator)
+{
+    ScrollAnimatorBase::trace(visitor);
+}
+
 } // namespace blink
diff --git a/third_party/WebKit/Source/platform/scroll/ScrollAnimator.h b/third_party/WebKit/Source/platform/scroll/ScrollAnimator.h
index ae84f9c..257f734 100644
--- a/third_party/WebKit/Source/platform/scroll/ScrollAnimator.h
+++ b/third_party/WebKit/Source/platform/scroll/ScrollAnimator.h
@@ -40,7 +40,7 @@
 
 class ScrollAnimatorTest;
 
-class PLATFORM_EXPORT ScrollAnimator : public ScrollAnimatorBase {
+class PLATFORM_EXPORT ScrollAnimator final : public ScrollAnimatorBase {
 public:
     explicit ScrollAnimator(ScrollableArea*, WTF::TimeFunction = WTF::monotonicallyIncreasingTime);
     ~ScrollAnimator() override;
@@ -52,6 +52,8 @@
     void serviceScrollAnimations() override;
     bool hasRunningAnimation() const override;
 
+    DECLARE_VIRTUAL_TRACE();
+
 protected:
     void animationTimerFired();
 
diff --git a/third_party/WebKit/Source/platform/scroll/ScrollAnimatorBase.cpp b/third_party/WebKit/Source/platform/scroll/ScrollAnimatorBase.cpp
index 8971694d..78d359c 100644
--- a/third_party/WebKit/Source/platform/scroll/ScrollAnimatorBase.cpp
+++ b/third_party/WebKit/Source/platform/scroll/ScrollAnimatorBase.cpp
@@ -95,4 +95,9 @@
     return std::max(std::min(pos, maxScrollPos), minScrollPos);
 }
 
+DEFINE_TRACE(ScrollAnimatorBase)
+{
+    visitor->trace(m_scrollableArea);
+}
+
 } // namespace blink
diff --git a/third_party/WebKit/Source/platform/scroll/ScrollAnimatorBase.h b/third_party/WebKit/Source/platform/scroll/ScrollAnimatorBase.h
index 0917eea..0a561831 100644
--- a/third_party/WebKit/Source/platform/scroll/ScrollAnimatorBase.h
+++ b/third_party/WebKit/Source/platform/scroll/ScrollAnimatorBase.h
@@ -44,12 +44,14 @@
 class ScrollableArea;
 class Scrollbar;
 
-class PLATFORM_EXPORT ScrollAnimatorBase {
+class PLATFORM_EXPORT ScrollAnimatorBase : public NoBaseWillBeGarbageCollectedFinalized<ScrollAnimatorBase> {
 public:
-    static PassOwnPtr<ScrollAnimatorBase> create(ScrollableArea*);
+    static PassOwnPtrWillBeRawPtr<ScrollAnimatorBase> create(ScrollableArea*);
 
     virtual ~ScrollAnimatorBase();
 
+    virtual void dispose() { }
+
     // Computes a scroll destination for the given parameters.  The returned
     // ScrollResultOneDimensional will have didScroll set to false if already at
     // the destination.  Otherwise, starts scrolling towards the destination and
@@ -99,13 +101,15 @@
     virtual void notifyContentAreaScrolled(const FloatSize&) { }
 
     virtual bool setScrollbarsVisibleForTesting(bool) { return false; }
+
+    DECLARE_VIRTUAL_TRACE();
+
 protected:
     explicit ScrollAnimatorBase(ScrollableArea*);
 
     virtual void notifyPositionChanged();
 
-    GC_PLUGIN_IGNORE("509911")
-    ScrollableArea* m_scrollableArea;
+    RawPtrWillBeMember<ScrollableArea> m_scrollableArea;
     float m_currentPosX; // We avoid using a FloatPoint in order to reduce
     float m_currentPosY; // subclass code complexity.
 
diff --git a/third_party/WebKit/Source/platform/scroll/ScrollAnimatorTest.cpp b/third_party/WebKit/Source/platform/scroll/ScrollAnimatorTest.cpp
index 310b11dd..70d1e47 100644
--- a/third_party/WebKit/Source/platform/scroll/ScrollAnimatorTest.cpp
+++ b/third_party/WebKit/Source/platform/scroll/ScrollAnimatorTest.cpp
@@ -104,7 +104,7 @@
 TEST(ScrollAnimatorTest, Enabled)
 {
     OwnPtrWillBeRawPtr<MockScrollableArea> scrollableArea = MockScrollableArea::create(true);
-    OwnPtr<ScrollAnimator> scrollAnimator = adoptPtr(new ScrollAnimator(scrollableArea.get(), getMockedTime));
+    OwnPtrWillBeRawPtr<ScrollAnimator> scrollAnimator = adoptPtrWillBeNoop(new ScrollAnimator(scrollableArea.get(), getMockedTime));
 
     EXPECT_CALL(*scrollableArea, minimumScrollPosition()).Times(AtLeast(1)).WillRepeatedly(Return(IntPoint()));
     EXPECT_CALL(*scrollableArea, maximumScrollPosition()).Times(AtLeast(1)).WillRepeatedly(Return(IntPoint(1000, 1000)));
@@ -172,7 +172,7 @@
 TEST(ScrollAnimatorTest, Disabled)
 {
     OwnPtrWillBeRawPtr<MockScrollableArea> scrollableArea = MockScrollableArea::create(false);
-    OwnPtr<ScrollAnimator> scrollAnimator = adoptPtr(new ScrollAnimator(scrollableArea.get(), getMockedTime));
+    OwnPtrWillBeRawPtr<ScrollAnimator> scrollAnimator = adoptPtrWillBeNoop(new ScrollAnimator(scrollableArea.get(), getMockedTime));
 
     EXPECT_CALL(*scrollableArea, minimumScrollPosition()).Times(AtLeast(1)).WillRepeatedly(Return(IntPoint()));
     EXPECT_CALL(*scrollableArea, maximumScrollPosition()).Times(AtLeast(1)).WillRepeatedly(Return(IntPoint(1000, 1000)));
diff --git a/third_party/WebKit/Source/platform/scroll/ScrollableArea.cpp b/third_party/WebKit/Source/platform/scroll/ScrollableArea.cpp
index 85016be..14086dc 100644
--- a/third_party/WebKit/Source/platform/scroll/ScrollableArea.cpp
+++ b/third_party/WebKit/Source/platform/scroll/ScrollableArea.cpp
@@ -54,7 +54,7 @@
 #if ENABLE(ASSERT) && ENABLE(OILPAN)
     VerifyEagerFinalization verifyEager;
 #endif
-    void* pointer;
+    OwnPtrWillBeMember<void*> pointer[2];
     unsigned bitfields : 16;
     IntPoint origin;
 };
@@ -93,29 +93,28 @@
 
 void ScrollableArea::clearScrollAnimators()
 {
-    m_animators.clear();
+#if OS(MACOSX) && ENABLE(OILPAN)
+    if (m_scrollAnimator)
+        m_scrollAnimator->dispose();
+#endif
+    m_scrollAnimator.clear();
+    m_programmaticScrollAnimator.clear();
 }
 
 ScrollAnimatorBase* ScrollableArea::scrollAnimator() const
 {
-    if (!m_animators)
-        m_animators = adoptPtr(new ScrollableAreaAnimators);
+    if (!m_scrollAnimator)
+        m_scrollAnimator = ScrollAnimatorBase::create(const_cast<ScrollableArea*>(this));
 
-    if (!m_animators->scrollAnimator)
-        m_animators->scrollAnimator = ScrollAnimatorBase::create(const_cast<ScrollableArea*>(this));
-
-    return m_animators->scrollAnimator.get();
+    return m_scrollAnimator.get();
 }
 
 ProgrammaticScrollAnimator* ScrollableArea::programmaticScrollAnimator() const
 {
-    if (!m_animators)
-        m_animators = adoptPtr(new ScrollableAreaAnimators);
+    if (!m_programmaticScrollAnimator)
+        m_programmaticScrollAnimator = ProgrammaticScrollAnimator::create(const_cast<ScrollableArea*>(this));
 
-    if (!m_animators->programmaticScrollAnimator)
-        m_animators->programmaticScrollAnimator = ProgrammaticScrollAnimator::create(const_cast<ScrollableArea*>(this));
-
-    return m_animators->programmaticScrollAnimator.get();
+    return m_programmaticScrollAnimator.get();
 }
 
 void ScrollableArea::setScrollOrigin(const IntPoint& origin)
@@ -584,4 +583,10 @@
 
 }
 
+DEFINE_TRACE(ScrollableArea)
+{
+    visitor->trace(m_scrollAnimator);
+    visitor->trace(m_programmaticScrollAnimator);
+}
+
 } // namespace blink
diff --git a/third_party/WebKit/Source/platform/scroll/ScrollableArea.h b/third_party/WebKit/Source/platform/scroll/ScrollableArea.h
index 390fea4..d643a1a 100644
--- a/third_party/WebKit/Source/platform/scroll/ScrollableArea.h
+++ b/third_party/WebKit/Source/platform/scroll/ScrollableArea.h
@@ -126,13 +126,10 @@
     ScrollAnimatorBase* scrollAnimator() const;
 
     // This getter will return null if the ScrollAnimatorBase hasn't been created yet.
-    ScrollAnimatorBase* existingScrollAnimator() const { return m_animators ? m_animators->scrollAnimator.get() : 0; }
+    ScrollAnimatorBase* existingScrollAnimator() const { return m_scrollAnimator.get(); }
 
     ProgrammaticScrollAnimator* programmaticScrollAnimator() const;
-    ProgrammaticScrollAnimator* existingProgrammaticScrollAnimator() const
-    {
-        return m_animators ? m_animators->programmaticScrollAnimator.get() : 0;
-    }
+    ProgrammaticScrollAnimator* existingProgrammaticScrollAnimator() const { return m_programmaticScrollAnimator.get(); }
 
     const IntPoint& scrollOrigin() const { return m_scrollOrigin; }
     bool scrollOriginChanged() const { return m_scrollOriginChanged; }
@@ -278,7 +275,7 @@
 
     // Need to promptly let go of owned animator objects.
     EAGERLY_FINALIZE();
-    DEFINE_INLINE_VIRTUAL_TRACE() { }
+    DECLARE_VIRTUAL_TRACE();
 
 protected:
     ScrollableArea();
@@ -325,12 +322,8 @@
     virtual int documentStep(ScrollbarOrientation) const;
     virtual float pixelStep(ScrollbarOrientation) const;
 
-    struct ScrollableAreaAnimators {
-        OwnPtr<ScrollAnimatorBase> scrollAnimator;
-        OwnPtr<ProgrammaticScrollAnimator> programmaticScrollAnimator;
-    };
-
-    mutable OwnPtr<ScrollableAreaAnimators> m_animators;
+    mutable OwnPtrWillBeMember<ScrollAnimatorBase> m_scrollAnimator;
+    mutable OwnPtrWillBeMember<ProgrammaticScrollAnimator> m_programmaticScrollAnimator;
 
     unsigned m_inLiveResize : 1;
 
diff --git a/third_party/WebKit/Source/platform/text/TextCheckerClient.h b/third_party/WebKit/Source/platform/text/TextCheckerClient.h
index dbdcee0..90743c3 100644
--- a/third_party/WebKit/Source/platform/text/TextCheckerClient.h
+++ b/third_party/WebKit/Source/platform/text/TextCheckerClient.h
@@ -41,7 +41,6 @@
 public:
     virtual ~TextCheckerClient() { }
 
-    virtual bool shouldEraseMarkersAfterChangeSelection(TextCheckingType) const = 0;
     virtual void checkSpellingOfString(const String&, int* misspellingLocation, int* misspellingLength) = 0;
     virtual void checkGrammarOfString(const String&, Vector<GrammarDetail>&, int* badGrammarLocation, int* badGrammarLength) = 0;
     virtual void requestCheckingOfString(PassRefPtrWillBeRawPtr<TextCheckingRequest>) = 0;
diff --git a/third_party/WebKit/Source/web/FrameLoaderClientImpl.cpp b/third_party/WebKit/Source/web/FrameLoaderClientImpl.cpp
index 69945ad..19de8ca 100644
--- a/third_party/WebKit/Source/web/FrameLoaderClientImpl.cpp
+++ b/third_party/WebKit/Source/web/FrameLoaderClientImpl.cpp
@@ -99,7 +99,6 @@
 #include "web/WebDevToolsFrontendImpl.h"
 #include "web/WebLocalFrameImpl.h"
 #include "web/WebPluginContainerImpl.h"
-#include "web/WebPluginLoadObserver.h"
 #include "web/WebViewImpl.h"
 #include "wtf/StringExtras.h"
 #include "wtf/text/CString.h"
@@ -494,37 +493,17 @@
 void FrameLoaderClientImpl::dispatchDidFailProvisionalLoad(
     const ResourceError& error, HistoryCommitType commitType)
 {
-    OwnPtrWillBeRawPtr<WebPluginLoadObserver> observer = pluginLoadObserver(m_webFrame->frame()->loader().provisionalDocumentLoader());
     m_webFrame->didFail(error, true, commitType);
-    if (observer)
-        observer->didFailLoading(error);
 }
 
 void FrameLoaderClientImpl::dispatchDidFailLoad(const ResourceError& error, HistoryCommitType commitType)
 {
-    OwnPtrWillBeRawPtr<WebPluginLoadObserver> observer = pluginLoadObserver(m_webFrame->frame()->loader().documentLoader());
     m_webFrame->didFail(error, false, commitType);
-    if (observer)
-        observer->didFailLoading(error);
-
-    // Don't clear the redirect chain, this will happen in the middle of client
-    // redirects, and we need the context. The chain will be cleared when the
-    // provisional load succeeds or fails, not the "real" one.
 }
 
 void FrameLoaderClientImpl::dispatchDidFinishLoad()
 {
-    OwnPtrWillBeRawPtr<WebPluginLoadObserver> observer = pluginLoadObserver(m_webFrame->frame()->loader().documentLoader());
-
-    if (m_webFrame->client())
-        m_webFrame->client()->didFinishLoad(m_webFrame);
-
-    if (observer)
-        observer->didFinishLoading();
-
-    // Don't clear the redirect chain, this will happen in the middle of client
-    // redirects, and we need the context. The chain will be cleared when the
-    // provisional load succeeds or fails, not the "real" one.
+    m_webFrame->didFinish();
 }
 
 void FrameLoaderClientImpl::dispatchDidChangeThemeColor()
@@ -883,11 +862,6 @@
     return ObjectContentNone;
 }
 
-PassOwnPtrWillBeRawPtr<WebPluginLoadObserver> FrameLoaderClientImpl::pluginLoadObserver(DocumentLoader* loader)
-{
-    return WebDataSourceImpl::fromDocumentLoader(loader)->releasePluginLoadObserver();
-}
-
 WebCookieJar* FrameLoaderClientImpl::cookieJar() const
 {
     if (!m_webFrame->client())
@@ -1001,12 +975,6 @@
     return adoptPtr(m_webFrame->client()->createApplicationCacheHost(m_webFrame, client));
 }
 
-void FrameLoaderClientImpl::didStopAllLoaders()
-{
-    if (m_webFrame->client())
-        m_webFrame->client()->didAbortLoading(m_webFrame);
-}
-
 void FrameLoaderClientImpl::dispatchDidChangeManifest()
 {
     if (m_webFrame->client())
diff --git a/third_party/WebKit/Source/web/FrameLoaderClientImpl.h b/third_party/WebKit/Source/web/FrameLoaderClientImpl.h
index 3cdeabc4..360f5b00 100644
--- a/third_party/WebKit/Source/web/FrameLoaderClientImpl.h
+++ b/third_party/WebKit/Source/web/FrameLoaderClientImpl.h
@@ -41,7 +41,6 @@
 namespace blink {
 
 class WebLocalFrameImpl;
-class WebPluginLoadObserver;
 
 class FrameLoaderClientImpl final : public FrameLoaderClient {
 public:
@@ -171,8 +170,6 @@
 
     PassOwnPtr<WebApplicationCacheHost> createApplicationCacheHost(WebApplicationCacheHostClient*) override;
 
-    void didStopAllLoaders() override;
-
     void dispatchDidChangeManifest() override;
 
     unsigned backForwardLength() override;
@@ -184,8 +181,6 @@
 
     bool isFrameLoaderClientImpl() const override { return true; }
 
-    PassOwnPtrWillBeRawPtr<WebPluginLoadObserver> pluginLoadObserver(DocumentLoader*);
-
     // The WebFrame that owns this object and manages its lifetime. Therefore,
     // the web frame object is guaranteed to exist.
     RawPtrWillBeMember<WebLocalFrameImpl> m_webFrame;
diff --git a/third_party/WebKit/Source/web/RemoteFrameClientImpl.cpp b/third_party/WebKit/Source/web/RemoteFrameClientImpl.cpp
index 9250810..fde5147 100644
--- a/third_party/WebKit/Source/web/RemoteFrameClientImpl.cpp
+++ b/third_party/WebKit/Source/web/RemoteFrameClientImpl.cpp
@@ -188,4 +188,9 @@
     m_webFrame->client()->frameRectsChanged(frameRect);
 }
 
+void RemoteFrameClientImpl::advanceFocus(WebFocusType type, LocalFrame* source)
+{
+    m_webFrame->client()->advanceFocus(type, WebLocalFrameImpl::fromFrame(source));
+}
+
 } // namespace blink
diff --git a/third_party/WebKit/Source/web/RemoteFrameClientImpl.h b/third_party/WebKit/Source/web/RemoteFrameClientImpl.h
index eb2342d8..388c808f 100644
--- a/third_party/WebKit/Source/web/RemoteFrameClientImpl.h
+++ b/third_party/WebKit/Source/web/RemoteFrameClientImpl.h
@@ -36,6 +36,7 @@
     unsigned backForwardLength() override;
     void forwardInputEvent(Event*) override;
     void frameRectsChanged(const IntRect& frameRect) override;
+    void advanceFocus(WebFocusType, LocalFrame*) override;
 
     WebRemoteFrameImpl* webFrame() const { return m_webFrame; }
 
diff --git a/third_party/WebKit/Source/web/SpellCheckerClientImpl.cpp b/third_party/WebKit/Source/web/SpellCheckerClientImpl.cpp
index 342ae99..5d132f1a 100644
--- a/third_party/WebKit/Source/web/SpellCheckerClientImpl.cpp
+++ b/third_party/WebKit/Source/web/SpellCheckerClientImpl.cpp
@@ -115,21 +115,6 @@
     }
 }
 
-// TODO(yosin): We should get rid of
-// |SepllCheckerClient::isGrammarCheckingEnabled()| as it always true.
-bool SpellCheckerClientImpl::isGrammarCheckingEnabled()
-{
-    return true;
-}
-
-// TODO(yosin): We should get rid of
-// |TextCheckerClient::shouldEraseMarkersAfterChangeSelection()| as it always
-// false.
-bool SpellCheckerClientImpl::shouldEraseMarkersAfterChangeSelection(TextCheckingType type) const
-{
-    return false;
-}
-
 void SpellCheckerClientImpl::checkSpellingOfString(const String& text, int* misspellingLocation, int* misspellingLength)
 {
     // SpellCheckWord will write (0, 0) into the output vars, which is what our
diff --git a/third_party/WebKit/Source/web/SpellCheckerClientImpl.h b/third_party/WebKit/Source/web/SpellCheckerClientImpl.h
index cf96ecf..4755b19 100644
--- a/third_party/WebKit/Source/web/SpellCheckerClientImpl.h
+++ b/third_party/WebKit/Source/web/SpellCheckerClientImpl.h
@@ -47,8 +47,6 @@
 
     bool isContinuousSpellCheckingEnabled() override;
     void toggleContinuousSpellChecking() override;
-    bool isGrammarCheckingEnabled() override;
-    bool shouldEraseMarkersAfterChangeSelection(TextCheckingType) const override;
     void checkSpellingOfString(const String&, int* misspellingLocation, int* misspellingLength) override;
     void checkGrammarOfString(const String&, Vector<GrammarDetail>&,
         int* badGrammarLocation, int* badGrammarLength) override;
diff --git a/third_party/WebKit/Source/web/WebCache.cpp b/third_party/WebKit/Source/web/WebCache.cpp
index fc115da9..eb0dee08 100644
--- a/third_party/WebKit/Source/web/WebCache.cpp
+++ b/third_party/WebKit/Source/web/WebCache.cpp
@@ -93,11 +93,4 @@
         memset(result, 0, sizeof(WebCache::ResourceTypeStats));
 }
 
-void WebCache::pruneAll()
-{
-    MemoryCache* cache = memoryCache();
-    if (cache)
-        cache->pruneAll();
-}
-
 }  // namespace blink
diff --git a/third_party/WebKit/Source/web/WebDataSourceImpl.cpp b/third_party/WebKit/Source/web/WebDataSourceImpl.cpp
index 45a6748..455be26b 100644
--- a/third_party/WebKit/Source/web/WebDataSourceImpl.cpp
+++ b/third_party/WebKit/Source/web/WebDataSourceImpl.cpp
@@ -38,12 +38,6 @@
 
 namespace blink {
 
-static OwnPtrWillBePersistent<WebPluginLoadObserver>& nextPluginLoadObserver()
-{
-    DEFINE_STATIC_LOCAL(OwnPtrWillBePersistent<WebPluginLoadObserver>, nextPluginLoadObserver, ());
-    return nextPluginLoadObserver;
-}
-
 PassRefPtrWillBeRawPtr<WebDataSourceImpl> WebDataSourceImpl::create(LocalFrame* frame, const ResourceRequest& request, const SubstituteData& data)
 {
     return adoptRefWillBeNoop(new WebDataSourceImpl(frame, request, data));
@@ -137,25 +131,9 @@
     }
 }
 
-void WebDataSourceImpl::setNextPluginLoadObserver(PassOwnPtrWillBeRawPtr<WebPluginLoadObserver> observer)
-{
-    nextPluginLoadObserver() = observer;
-}
-
 WebDataSourceImpl::WebDataSourceImpl(LocalFrame* frame, const ResourceRequest& request, const SubstituteData& data)
     : DocumentLoader(frame, request, data)
 {
-    if (!nextPluginLoadObserver())
-        return;
-    // When a new frame is created, it initially gets a data source for an
-    // empty document. Then it is navigated to the source URL of the
-    // frame, which results in a second data source being created. We want
-    // to wait to attach the WebPluginLoadObserver to that data source.
-    if (request.url().isEmpty())
-        return;
-
-    ASSERT(nextPluginLoadObserver()->url() == WebURL(request.url()));
-    m_pluginLoadObserver = nextPluginLoadObserver().release();
 }
 
 WebDataSourceImpl::~WebDataSourceImpl()
@@ -170,12 +148,10 @@
 
     DocumentLoader::detachFromFrame();
     m_extraData.clear();
-    m_pluginLoadObserver.clear();
 }
 
 DEFINE_TRACE(WebDataSourceImpl)
 {
-    visitor->trace(m_pluginLoadObserver);
     DocumentLoader::trace(visitor);
 }
 
diff --git a/third_party/WebKit/Source/web/WebDataSourceImpl.h b/third_party/WebKit/Source/web/WebDataSourceImpl.h
index 77e8580..b948d879 100644
--- a/third_party/WebKit/Source/web/WebDataSourceImpl.h
+++ b/third_party/WebKit/Source/web/WebDataSourceImpl.h
@@ -37,7 +37,6 @@
 #include "platform/heap/Handle.h"
 #include "platform/weborigin/KURL.h"
 #include "public/web/WebDataSource.h"
-#include "web/WebPluginLoadObserver.h"
 #include "wtf/OwnPtr.h"
 #include "wtf/PassOwnPtr.h"
 #include "wtf/Vector.h"
@@ -70,9 +69,6 @@
 
     static WebNavigationType toWebNavigationType(NavigationType);
 
-    PassOwnPtrWillBeRawPtr<WebPluginLoadObserver> releasePluginLoadObserver() { return m_pluginLoadObserver.release(); }
-    static void setNextPluginLoadObserver(PassOwnPtrWillBeRawPtr<WebPluginLoadObserver>);
-
     DECLARE_VIRTUAL_TRACE();
 
 private:
@@ -88,7 +84,6 @@
     mutable WrappedResourceResponse m_responseWrapper;
 
     OwnPtr<ExtraData> m_extraData;
-    OwnPtrWillBeMember<WebPluginLoadObserver> m_pluginLoadObserver;
 };
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/web/WebDocument.cpp b/third_party/WebKit/Source/web/WebDocument.cpp
index 450ccaa..f3b4146c7 100644
--- a/third_party/WebKit/Source/web/WebDocument.cpp
+++ b/third_party/WebKit/Source/web/WebDocument.cpp
@@ -216,7 +216,7 @@
     ASSERT(document);
     RefPtrWillBeRawPtr<StyleSheetContents> parsedSheet = StyleSheetContents::create(CSSParserContext(*document, 0));
     parsedSheet->parseString(sourceCode);
-    document->styleEngine().addAuthorSheet(parsedSheet);
+    document->styleEngine().injectAuthorSheet(parsedSheet);
 }
 
 void WebDocument::watchCSSSelectors(const WebVector<WebString>& webSelectors)
diff --git a/third_party/WebKit/Source/web/WebFormControlElement.cpp b/third_party/WebKit/Source/web/WebFormControlElement.cpp
index c78a047..0c65d270e 100644
--- a/third_party/WebKit/Source/web/WebFormControlElement.cpp
+++ b/third_party/WebKit/Source/web/WebFormControlElement.cpp
@@ -83,6 +83,8 @@
         return constUnwrap<HTMLInputElement>()->shouldAutocomplete();
     if (isHTMLTextAreaElement(*m_private))
         return constUnwrap<HTMLTextAreaElement>()->shouldAutocomplete();
+    if (isHTMLSelectElement(*m_private))
+        return constUnwrap<HTMLSelectElement>()->shouldAutocomplete();
     return false;
 }
 
diff --git a/third_party/WebKit/Source/web/WebFrameWidgetImpl.cpp b/third_party/WebKit/Source/web/WebFrameWidgetImpl.cpp
index 46f9bc1..736a58a 100644
--- a/third_party/WebKit/Source/web/WebFrameWidgetImpl.cpp
+++ b/third_party/WebKit/Source/web/WebFrameWidgetImpl.cpp
@@ -604,6 +604,9 @@
 
 void WebFrameWidgetImpl::willCloseLayerTreeView()
 {
+    if (m_layerTreeView)
+        page()->willCloseLayerTreeView(*m_layerTreeView);
+
     setIsAcceleratedCompositingActive(false);
     m_layerTreeView = nullptr;
     m_layerTreeViewClosed = true;
@@ -985,6 +988,8 @@
         devTools->layerTreeViewChanged(m_layerTreeView);
 
     page()->settings().setAcceleratedCompositingEnabled(m_layerTreeView);
+    if (m_layerTreeView)
+        page()->layerTreeViewInitialized(*m_layerTreeView);
 
     // FIXME: only unittests, click to play, Android priting, and printing (for headers and footers)
     // make this assert necessary. We should make them not hit this code and then delete allowsBrokenNullLayerTreeView.
diff --git a/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp b/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp
index eb7bedf..89295a1 100644
--- a/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp
+++ b/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp
@@ -1971,12 +1971,27 @@
         return;
     WebURLError webError = error;
     WebHistoryCommitType webCommitType = static_cast<WebHistoryCommitType>(commitType);
+
+    if (WebPluginContainerImpl* plugin = pluginContainerFromFrame(frame()))
+        plugin->didFailLoading(error);
+
     if (wasProvisional)
         client()->didFailProvisionalLoad(this, webError, webCommitType);
     else
         client()->didFailLoad(this, webError, webCommitType);
 }
 
+void WebLocalFrameImpl::didFinish()
+{
+    if (!client())
+        return;
+
+    if (WebPluginContainerImpl* plugin = pluginContainerFromFrame(frame()))
+        plugin->didFinishLoading();
+
+    client()->didFinishLoad(this);
+}
+
 void WebLocalFrameImpl::setCanHaveScrollbars(bool canHaveScrollbars)
 {
     frame()->view()->setCanHaveScrollbars(canHaveScrollbars);
diff --git a/third_party/WebKit/Source/web/WebLocalFrameImpl.h b/third_party/WebKit/Source/web/WebLocalFrameImpl.h
index c2618b72..147c417 100644
--- a/third_party/WebKit/Source/web/WebLocalFrameImpl.h
+++ b/third_party/WebKit/Source/web/WebLocalFrameImpl.h
@@ -317,6 +317,7 @@
     void setFindEndstateFocusAndSelection();
 
     void didFail(const ResourceError&, bool wasProvisional, HistoryCommitType);
+    void didFinish();
 
     // Sets whether the WebLocalFrameImpl allows its document to be scrolled.
     // If the parameter is true, allow the document to be scrolled.
diff --git a/third_party/WebKit/Source/web/WebMemoryPressureListener.cpp b/third_party/WebKit/Source/web/WebMemoryPressureListener.cpp
new file mode 100644
index 0000000..42760fe
--- /dev/null
+++ b/third_party/WebKit/Source/web/WebMemoryPressureListener.cpp
@@ -0,0 +1,18 @@
+// Copyright (c) 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.
+
+#include "config.h"
+#include "public/web/WebMemoryPressureListener.h"
+
+#include "core/page/Page.h"
+#include "platform/MemoryPurgeController.h"
+
+namespace blink {
+
+void WebMemoryPressureListener::onMemoryPressure()
+{
+    Page::onMemoryPressure();
+}
+
+} // namespace blink
diff --git a/third_party/WebKit/Source/web/WebPagePopupImpl.cpp b/third_party/WebKit/Source/web/WebPagePopupImpl.cpp
index d41da16..296c0ace 100644
--- a/third_party/WebKit/Source/web/WebPagePopupImpl.cpp
+++ b/third_party/WebKit/Source/web/WebPagePopupImpl.cpp
@@ -344,6 +344,7 @@
             m_layerTreeView->setVisible(true);
             m_isAcceleratedCompositingActive = true;
             m_layerTreeView->setDeviceScaleFactor(m_webView->deviceScaleFactor());
+            m_page->layerTreeViewInitialized(*m_layerTreeView);
         } else {
             m_isAcceleratedCompositingActive = false;
         }
@@ -361,6 +362,9 @@
 
 void WebPagePopupImpl::willCloseLayerTreeView()
 {
+    if (m_page && m_layerTreeView)
+        m_page->willCloseLayerTreeView(*m_layerTreeView);
+
     setIsAcceleratedCompositingActive(false);
     m_layerTreeView = 0;
 }
diff --git a/third_party/WebKit/Source/web/WebPluginContainerImpl.cpp b/third_party/WebKit/Source/web/WebPluginContainerImpl.cpp
index 10a10cf..8de3047c 100644
--- a/third_party/WebKit/Source/web/WebPluginContainerImpl.cpp
+++ b/third_party/WebKit/Source/web/WebPluginContainerImpl.cpp
@@ -493,23 +493,12 @@
     return toCoreString(v8::Local<v8::String>::Cast(result));
 }
 
-void WebPluginContainerImpl::loadFrameRequest(const WebURLRequest& request, const WebString& target, bool notifyNeeded, void* notifyData)
+void WebPluginContainerImpl::loadFrameRequest(const WebURLRequest& request, const WebString& target)
 {
     LocalFrame* frame = m_element->document().frame();
     if (!frame || !frame->loader().documentLoader())
         return;  // FIXME: send a notification in this case?
 
-    if (notifyNeeded) {
-        // FIXME: This is a bit of hack to allow us to observe completion of
-        // our frame request.  It would be better to evolve FrameLoader to
-        // support a completion callback instead.
-        OwnPtrWillBeRawPtr<WebPluginLoadObserver> observer = WebPluginLoadObserver::create(this, request.url(), notifyData);
-#if !ENABLE(OILPAN)
-        m_pluginLoadObservers.append(observer.get());
-#endif
-        WebDataSourceImpl::setNextPluginLoadObserver(observer.release());
-    }
-
     FrameLoadRequest frameRequest(frame->document(), request.toResourceRequest(), target);
     frame->loader().load(frameRequest);
 }
@@ -686,16 +675,6 @@
     return m_wantsWheelEvents;
 }
 
-#if !ENABLE(OILPAN)
-void WebPluginContainerImpl::willDestroyPluginLoadObserver(WebPluginLoadObserver* observer)
-{
-    size_t pos = m_pluginLoadObservers.find(observer);
-    if (pos == kNotFound)
-        return;
-    m_pluginLoadObservers.remove(pos);
-}
-#endif
-
 // Private methods -------------------------------------------------------------
 
 WebPluginContainerImpl::WebPluginContainerImpl(HTMLPlugInElement* element, WebPlugin* webPlugin)
@@ -731,11 +710,6 @@
     if (m_element && m_touchEventRequestType != TouchEventRequestTypeNone && m_element->document().frameHost())
         m_element->document().frameHost()->eventHandlerRegistry().didRemoveEventHandler(*m_element, EventHandlerRegistry::TouchEvent);
 
-#if !ENABLE(OILPAN)
-    for (const auto& observer : m_pluginLoadObservers)
-        observer->clearPluginContainer();
-#endif
-
     if (m_webPlugin) {
         RELEASE_ASSERT(!m_webPlugin->container() || m_webPlugin->container() == this);
         m_webPlugin->destroy();
@@ -747,9 +721,6 @@
         m_webLayer = nullptr;
     }
 
-#if !ENABLE(OILPAN)
-    m_pluginLoadObservers.clear();
-#endif
     m_element = nullptr;
 }
 
diff --git a/third_party/WebKit/Source/web/WebPluginContainerImpl.h b/third_party/WebKit/Source/web/WebPluginContainerImpl.h
index d0be624..a79503b 100644
--- a/third_party/WebKit/Source/web/WebPluginContainerImpl.h
+++ b/third_party/WebKit/Source/web/WebPluginContainerImpl.h
@@ -55,7 +55,6 @@
 class ResourceResponse;
 class TouchEvent;
 class WebPlugin;
-class WebPluginLoadObserver;
 class WheelEvent;
 class Widget;
 struct WebPrintParams;
@@ -108,7 +107,7 @@
     NPObject* scriptableObjectForElement() override;
     v8::Local<v8::Object> v8ObjectForElement() override;
     WebString executeScriptURL(const WebURL&, bool popupsAllowed) override;
-    void loadFrameRequest(const WebURLRequest&, const WebString& target, bool notifyNeeded, void* notifyData) override;
+    void loadFrameRequest(const WebURLRequest&, const WebString& target) override;
     bool isRectTopmost(const WebRect&) override;
     void requestTouchEventType(TouchEventRequestType) override;
     void setWantsWheelEvents(bool) override;
@@ -153,12 +152,8 @@
     // Resource load events for the plugin's source data:
     void didReceiveResponse(const ResourceResponse&) override;
     void didReceiveData(const char *data, int dataLength) override;
-    void didFinishLoading() override;
-    void didFailLoading(const ResourceError&) override;
-
-#if !ENABLE(OILPAN)
-    void willDestroyPluginLoadObserver(WebPluginLoadObserver*);
-#endif
+    void didFinishLoading();
+    void didFailLoading(const ResourceError&);
 
     DECLARE_VIRTUAL_TRACE();
     void dispose() override;
@@ -202,9 +197,6 @@
 
     RawPtrWillBeMember<HTMLPlugInElement> m_element;
     WebPlugin* m_webPlugin;
-#if !ENABLE(OILPAN)
-    Vector<WebPluginLoadObserver*> m_pluginLoadObservers;
-#endif
 
     WebLayer* m_webLayer;
 
diff --git a/third_party/WebKit/Source/web/WebPluginLoadObserver.cpp b/third_party/WebKit/Source/web/WebPluginLoadObserver.cpp
deleted file mode 100644
index 911a7519..0000000
--- a/third_party/WebKit/Source/web/WebPluginLoadObserver.cpp
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2009 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.
- */
-
-#include "config.h"
-#include "web/WebPluginLoadObserver.h"
-
-#include "public/web/WebPlugin.h"
-#include "web/WebPluginContainerImpl.h"
-
-namespace blink {
-
-WebPluginLoadObserver::~WebPluginLoadObserver()
-{
-#if !ENABLE(OILPAN)
-    if (m_pluginContainer)
-        m_pluginContainer->willDestroyPluginLoadObserver(this);
-#endif
-}
-
-DEFINE_TRACE(WebPluginLoadObserver)
-{
-    visitor->trace(m_pluginContainer);
-}
-
-void WebPluginLoadObserver::didFinishLoading()
-{
-    if (!m_pluginContainer)
-        return;
-    if (WebPlugin* plugin = m_pluginContainer->plugin())
-        plugin->didFinishLoadingFrameRequest(m_notifyURL, m_notifyData);
-}
-
-void WebPluginLoadObserver::didFailLoading(const WebURLError& error)
-{
-    if (!m_pluginContainer)
-        return;
-    if (WebPlugin* plugin = m_pluginContainer->plugin())
-        plugin->didFailLoadingFrameRequest(m_notifyURL, m_notifyData, error);
-}
-
-} // namespace blink
diff --git a/third_party/WebKit/Source/web/WebPluginLoadObserver.h b/third_party/WebKit/Source/web/WebPluginLoadObserver.h
deleted file mode 100644
index 25ecd7a1..0000000
--- a/third_party/WebKit/Source/web/WebPluginLoadObserver.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 2009 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 WebPluginLoadObserver_h
-#define WebPluginLoadObserver_h
-
-#include "platform/heap/Handle.h"
-#include "public/platform/WebURL.h"
-
-namespace blink {
-
-class WebPluginContainerImpl;
-struct WebURLError;
-
-class WebPluginLoadObserver final : public NoBaseWillBeGarbageCollectedFinalized<WebPluginLoadObserver> {
-public:
-    static PassOwnPtrWillBeRawPtr<WebPluginLoadObserver> create(WebPluginContainerImpl* pluginContainer, const WebURL& notifyURL, void* notifyData)
-    {
-        return adoptPtrWillBeNoop(new WebPluginLoadObserver(pluginContainer, notifyURL, notifyData));
-    }
-    ~WebPluginLoadObserver();
-
-    const WebURL& url() const { return m_notifyURL; }
-
-#if !ENABLE(OILPAN)
-    void clearPluginContainer() { m_pluginContainer = nullptr; }
-#endif
-    void didFinishLoading();
-    void didFailLoading(const WebURLError&);
-
-    DECLARE_TRACE();
-
-private:
-    WebPluginLoadObserver(WebPluginContainerImpl* pluginContainer, const WebURL& notifyURL, void* notifyData)
-        : m_pluginContainer(pluginContainer)
-        , m_notifyURL(notifyURL)
-        , m_notifyData(notifyData)
-    {
-    }
-
-    RawPtrWillBeWeakMember<WebPluginContainerImpl> m_pluginContainer;
-    WebURL m_notifyURL;
-    void* m_notifyData;
-};
-
-} // namespace blink
-
-#endif
diff --git a/third_party/WebKit/Source/web/WebSettingsImpl.cpp b/third_party/WebKit/Source/web/WebSettingsImpl.cpp
index c6ec5af..6df9dad 100644
--- a/third_party/WebKit/Source/web/WebSettingsImpl.cpp
+++ b/third_party/WebKit/Source/web/WebSettingsImpl.cpp
@@ -569,11 +569,6 @@
     m_settings->setHyperlinkAuditingEnabled(enabled);
 }
 
-void WebSettingsImpl::setAsynchronousSpellCheckingEnabled(bool enabled)
-{
-    m_settings->setAsynchronousSpellCheckingEnabled(enabled);
-}
-
 void WebSettingsImpl::setAutoplayExperimentMode(const WebString& mode)
 {
     m_settings->setAutoplayExperimentMode(mode);
diff --git a/third_party/WebKit/Source/web/WebSettingsImpl.h b/third_party/WebKit/Source/web/WebSettingsImpl.h
index 6835ec36..3ee436a 100644
--- a/third_party/WebKit/Source/web/WebSettingsImpl.h
+++ b/third_party/WebKit/Source/web/WebSettingsImpl.h
@@ -63,7 +63,6 @@
     void setAllowUniversalAccessFromFileURLs(bool) override;
     void setAntialiased2dCanvasEnabled(bool) override;
     void setAntialiasedClips2dCanvasEnabled(bool) override;
-    void setAsynchronousSpellCheckingEnabled(bool) override;
     void setAutoplayExperimentMode(const WebString&) override;
     void setAutoZoomFocusedNodeToLegibleScale(bool) override;
     void setCaretBrowsingEnabled(bool) override;
diff --git a/third_party/WebKit/Source/web/WebViewImpl.cpp b/third_party/WebKit/Source/web/WebViewImpl.cpp
index 86cf714..e6417fad 100644
--- a/third_party/WebKit/Source/web/WebViewImpl.cpp
+++ b/third_party/WebKit/Source/web/WebViewImpl.cpp
@@ -2690,8 +2690,8 @@
         m_linkHighlightsTimeline.clear();
     }
 
-    if (page())
-        page()->willCloseLayerTreeView();
+    if (m_layerTreeView)
+        page()->willCloseLayerTreeView(*m_layerTreeView);
 
     setRootGraphicsLayer(nullptr);
     m_layerTreeView = nullptr;
@@ -2968,6 +2968,13 @@
     page()->focusController().advanceFocus(reverse ? WebFocusTypeBackward : WebFocusTypeForward);
 }
 
+void WebViewImpl::advanceFocusAcrossFrames(WebFocusType type, WebRemoteFrame* from, WebLocalFrame* to)
+{
+    // TODO(alexmos): Pass in proper with sourceCapabilities.
+    page()->focusController().advanceFocusAcrossFrames(
+        type, toWebRemoteFrameImpl(from)->frame(), toWebLocalFrameImpl(to)->frame());
+}
+
 double WebViewImpl::zoomLevel()
 {
     return m_zoomLevel;
@@ -3771,6 +3778,13 @@
     }
 }
 
+void WebViewImpl::didCloseContextMenu()
+{
+    LocalFrame* frame = m_page->focusController().focusedFrame();
+    if (frame)
+        frame->selection().setCaretBlinkingSuspended(false);
+}
+
 void WebViewImpl::extractSmartClipData(WebRect rectInViewport, WebString& clipText, WebString& clipHtml, WebRect& clipRectInViewport)
 {
     LocalFrame* localFrame = toLocalFrame(focusedCoreFrame());
@@ -4242,6 +4256,8 @@
         devTools->layerTreeViewChanged(m_layerTreeView);
 
     m_page->settings().setAcceleratedCompositingEnabled(m_layerTreeView);
+    if (m_layerTreeView)
+        m_page->layerTreeViewInitialized(*m_layerTreeView);
 
     // FIXME: only unittests, click to play, Android printing, and printing (for headers and footers)
     // make this assert necessary. We should make them not hit this code and then delete allowsBrokenNullLayerTreeView.
diff --git a/third_party/WebKit/Source/web/WebViewImpl.h b/third_party/WebKit/Source/web/WebViewImpl.h
index 65458543..c4453c1 100644
--- a/third_party/WebKit/Source/web/WebViewImpl.h
+++ b/third_party/WebKit/Source/web/WebViewImpl.h
@@ -82,10 +82,12 @@
 class WebDevToolsAgentImpl;
 class WebElement;
 class WebLayerTreeView;
+class WebLocalFrame;
 class WebLocalFrameImpl;
 class WebImage;
 class WebPagePopupImpl;
 class WebPlugin;
+class WebRemoteFrame;
 class WebSelection;
 class WebSettingsImpl;
 class WebViewScheduler;
@@ -189,6 +191,7 @@
     void smoothScroll(int targetX, int targetY, long durationMs) override;
     void zoomToFindInPageRect(const WebRect&);
     void advanceFocus(bool reverse) override;
+    void advanceFocusAcrossFrames(WebFocusType, WebRemoteFrame* from, WebLocalFrame* to) override;
     double zoomLevel() override;
     double setZoomLevel(double) override;
     void zoomLimitsChanged(double minimumZoomLevel, double maximumZoomLevel) override;
@@ -262,6 +265,7 @@
                                     unsigned inactiveForegroundColor) override;
     void performCustomContextMenuAction(unsigned action) override;
     void showContextMenu() override;
+    void didCloseContextMenu() override;
     void extractSmartClipData(WebRect, WebString&, WebString&, WebRect&) override;
     void hidePopups() override;
     void setPageOverlayColor(WebColor) override;
diff --git a/third_party/WebKit/Source/web/tests/FakeWebPlugin.h b/third_party/WebKit/Source/web/tests/FakeWebPlugin.h
index 6fd138e..5b3f1c3 100644
--- a/third_party/WebKit/Source/web/tests/FakeWebPlugin.h
+++ b/third_party/WebKit/Source/web/tests/FakeWebPlugin.h
@@ -64,8 +64,6 @@
     void didReceiveData(const char* data, int dataLength) override { }
     void didFinishLoading() override { }
     void didFailLoading(const WebURLError&) override { }
-    void didFinishLoadingFrameRequest(const WebURL&, void* notifyData) override { }
-    void didFailLoadingFrameRequest(const WebURL&, void* notifyData, const WebURLError&) override { }
     bool isPlaceholder() override { return false; }
 
 protected:
diff --git a/third_party/WebKit/Source/web/tests/SpinLockTest.cpp b/third_party/WebKit/Source/web/tests/SpinLockTest.cpp
index 18abef9..7806b5b 100644
--- a/third_party/WebKit/Source/web/tests/SpinLockTest.cpp
+++ b/third_party/WebKit/Source/web/tests/SpinLockTest.cpp
@@ -44,7 +44,7 @@
 
 static const size_t bufferSize = 16;
 
-static int lock = 0;
+static SpinLock lock;
 
 static void fillBuffer(volatile char* buffer, char fillPattern)
 {
@@ -69,9 +69,8 @@
 static void threadMain(volatile char* buffer)
 {
     for (int i = 0; i < 500000; ++i) {
-        spinLockLock(&lock);
+        SpinLock::Guard guard(lock);
         changeAndCheckBuffer(buffer);
-        spinLockUnlock(&lock);
     }
 }
 
diff --git a/third_party/WebKit/Source/web/tests/TouchActionTest.cpp b/third_party/WebKit/Source/web/tests/TouchActionTest.cpp
index 0719ecf..82992c1 100644
--- a/third_party/WebKit/Source/web/tests/TouchActionTest.cpp
+++ b/third_party/WebKit/Source/web/tests/TouchActionTest.cpp
@@ -38,6 +38,7 @@
 #include "core/dom/shadow/ShadowRoot.h"
 #include "core/frame/FrameView.h"
 #include "core/frame/LocalFrame.h"
+#include "core/html/HTMLIFrameElement.h"
 #include "core/input/EventHandler.h"
 #include "core/layout/HitTestResult.h"
 #include "core/layout/LayoutTreeAsText.h"
@@ -54,6 +55,7 @@
 #include "public/web/WebViewClient.h"
 #include "public/web/WebWidgetClient.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "web/WebFrameImplBase.h"
 #include "web/WebViewImpl.h"
 #include "web/tests/FrameTestHelpers.h"
 
@@ -118,6 +120,7 @@
 protected:
     void runTouchActionTest(std::string file);
     void runShadowDOMTest(std::string file);
+    void runIFrameTest(std::string file);
     void sendTouchEvent(WebView*, WebInputEvent::Type, IntPoint clientPoint);
     WebView* setupTest(std::string file, TouchActionTrackingWebViewClient&);
     void runTestOnTree(ContainerNode* root, WebView*, TouchActionTrackingWebViewClient&);
@@ -173,6 +176,23 @@
     m_webViewHelper.reset(); // Explicitly reset to break dependency on locally scoped client.
 }
 
+void TouchActionTest::runIFrameTest(std::string file)
+{
+    TouchActionTrackingWebViewClient client;
+
+    WebView* webView = setupTest(file, client);
+    WebFrame* curFrame = webView->mainFrame()->firstChild();
+    ASSERT_TRUE(curFrame);
+
+    for (; curFrame; curFrame = curFrame->nextSibling()) {
+        // Oilpan: see runTouchActionTest() comment why these are persistent references.
+        RefPtrWillBePersistent<Document> contentDoc = static_cast<PassRefPtrWillBeRawPtr<Document>>(curFrame->document());
+        runTestOnTree(contentDoc.get(), webView, client);
+    }
+
+    m_webViewHelper.reset(); // Explicitly reset to break dependency on locally scoped client.
+}
+
 WebView* TouchActionTest::setupTest(std::string file, TouchActionTrackingWebViewClient& client)
 {
     URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL), WebString::fromUTF8(file));
@@ -224,33 +244,35 @@
         FloatRect clientFloatRect = FloatRect(r->left(), r->top(), r->width(), r->height());
         IntRect clientRect =  enclosedIntRect(clientFloatRect);
         for (int locIdx = 0; locIdx < 3; locIdx++) {
-            IntPoint clientPoint;
+            IntPoint framePoint;
             std::stringstream contextStream;
             contextStream << failureContext << " (";
             switch (locIdx) {
             case 0:
-                clientPoint = clientRect.center();
+                framePoint = clientRect.center();
                 contextStream << "center";
                 break;
             case 1:
-                clientPoint = clientRect.location();
+                framePoint = clientRect.location();
                 contextStream << "top-left";
                 break;
             case 2:
-                clientPoint = clientRect.maxXMaxYCorner();
-                clientPoint.move(-1, -1);
+                framePoint = clientRect.maxXMaxYCorner();
+                framePoint.move(-1, -1);
                 contextStream << "bottom-right";
                 break;
             default:
                 FAIL() << "Invalid location index.";
             }
-            contextStream << "=" << clientPoint.x() << "," << clientPoint.y() << ").";
+
+            IntPoint windowPoint = root->document().frame()->view()->convertToRootFrame(framePoint);
+            contextStream << "=" << windowPoint.x() << "," << windowPoint.y() << ").";
             std::string failureContextPos = contextStream.str();
 
-            LocalFrame* frame = root->document().frame();
-            FrameView* frameView = frame->view();
-            IntRect visibleRect = frameView->windowClipRect();
-            ASSERT_TRUE(visibleRect.contains(clientPoint)) << failureContextPos
+            LocalFrame* mainFrame = static_cast<LocalFrame*>(webView->mainFrame()->toImplBase()->frame());
+            FrameView* mainFrameView = mainFrame->view();
+            IntRect visibleRect = mainFrameView->windowClipRect();
+            ASSERT_TRUE(visibleRect.contains(windowPoint)) << failureContextPos
                 << " Test point not contained in visible area: " << visibleRect.x() << "," << visibleRect.y()
                 << "-" << visibleRect.maxX() << "," << visibleRect.maxY();
 
@@ -258,14 +280,14 @@
             // we intended. This is the easiest way for a test to be broken, but has nothing really
             // to do with touch action.
             // Note that we can't use WebView's hit test API because it doesn't look into shadow DOM.
-            IntPoint docPoint(frameView->rootFrameToContents(clientPoint));
-            HitTestResult result = frame->eventHandler().hitTestResultAtPoint(docPoint, HitTestRequest::ReadOnly | HitTestRequest::Active);
+            IntPoint docPoint(mainFrameView->frameToContents(windowPoint));
+            HitTestResult result = mainFrame->eventHandler().hitTestResultAtPoint(docPoint, HitTestRequest::ReadOnly | HitTestRequest::Active);
             ASSERT_EQ(element, result.innerElement()) << "Unexpected hit test result " << failureContextPos
                 << "  Got element: \"" << result.innerElement()->outerHTML().stripWhiteSpace().left(80).ascii().data() << "\""
                 << std::endl << "Document render tree:" << std::endl << externalRepresentation(root->document().frame()).utf8().data();
 
             // Now send the touch event and check any touch action result.
-            sendTouchEvent(webView, WebInputEvent::TouchStart, clientPoint);
+            sendTouchEvent(webView, WebInputEvent::TouchStart, windowPoint);
 
             AtomicString expectedAction = element->getAttribute("expected-action");
             if (expectedAction == "auto") {
@@ -283,9 +305,9 @@
                     } else if (expectedAction == "pan-y") {
                         EXPECT_EQ(WebTouchActionPanY, client.lastTouchAction()) << failureContextPos;
                     } else if (expectedAction == "pan-x-y") {
-                        EXPECT_EQ((WebTouchActionPanX | WebTouchActionPanY), client.lastTouchAction()) << failureContextPos;
+                        EXPECT_EQ((WebTouchActionPan), client.lastTouchAction()) << failureContextPos;
                     } else if (expectedAction == "manipulation") {
-                        EXPECT_EQ((WebTouchActionPanX | WebTouchActionPanY | WebTouchActionPinchZoom), client.lastTouchAction()) << failureContextPos;
+                        EXPECT_EQ((WebTouchActionManipulation), client.lastTouchAction()) << failureContextPos;
                     } else {
                         FAIL() << "Unrecognized expected-action \"" << expectedAction.ascii().data()
                             << "\" " << failureContextPos;
@@ -295,7 +317,7 @@
 
             // Reset webview touch state.
             client.reset();
-            sendTouchEvent(webView, WebInputEvent::TouchCancel, clientPoint);
+            sendTouchEvent(webView, WebInputEvent::TouchCancel, windowPoint);
             EXPECT_EQ(0, client.touchActionSetCount());
         }
     }
@@ -335,6 +357,11 @@
     runTouchActionTest("touch-action-overflow.html");
 }
 
+TEST_F(TouchActionTest, IFrame)
+{
+    runIFrameTest("touch-action-iframe.html");
+}
+
 TEST_F(TouchActionTest, ShadowDOM)
 {
     runShadowDOMTest("touch-action-shadow-dom.html");
diff --git a/third_party/WebKit/Source/web/tests/WebFrameTest.cpp b/third_party/WebKit/Source/web/tests/WebFrameTest.cpp
index a2e5930a..0e164e8 100644
--- a/third_party/WebKit/Source/web/tests/WebFrameTest.cpp
+++ b/third_party/WebKit/Source/web/tests/WebFrameTest.cpp
@@ -5180,7 +5180,6 @@
     Document* document = frame->frame()->document();
     Element* element = document->getElementById("data");
 
-    webViewHelper.webView()->settings()->setAsynchronousSpellCheckingEnabled(true);
     webViewHelper.webView()->settings()->setUnifiedTextCheckerEnabled(true);
     webViewHelper.webView()->settings()->setEditingBehavior(WebSettings::EditingBehaviorWin);
 
@@ -5213,7 +5212,6 @@
     Document* document = frame->frame()->document();
     Element* element = document->getElementById("data");
 
-    webViewHelper.webView()->settings()->setAsynchronousSpellCheckingEnabled(true);
     webViewHelper.webView()->settings()->setUnifiedTextCheckerEnabled(true);
     webViewHelper.webView()->settings()->setEditingBehavior(WebSettings::EditingBehaviorWin);
 
@@ -5244,7 +5242,6 @@
     Document* document = frame->document();
     Element* element = document->getElementById("data");
 
-    webViewHelper.webView()->settings()->setAsynchronousSpellCheckingEnabled(true);
     webViewHelper.webView()->settings()->setUnifiedTextCheckerEnabled(true);
     webViewHelper.webView()->settings()->setEditingBehavior(WebSettings::EditingBehaviorWin);
 
@@ -5280,7 +5277,6 @@
     Document* document = frame->frame()->document();
     Element* element = document->getElementById("data");
 
-    webViewHelper.webView()->settings()->setAsynchronousSpellCheckingEnabled(true);
     webViewHelper.webView()->settings()->setUnifiedTextCheckerEnabled(true);
     webViewHelper.webView()->settings()->setEditingBehavior(WebSettings::EditingBehaviorWin);
 
@@ -5357,7 +5353,6 @@
     Document* document = frame->frame()->document();
     Element* element = document->getElementById("data");
 
-    webViewHelper.webView()->settings()->setAsynchronousSpellCheckingEnabled(true);
     webViewHelper.webView()->settings()->setUnifiedTextCheckerEnabled(true);
     webViewHelper.webView()->settings()->setEditingBehavior(WebSettings::EditingBehaviorWin);
 
@@ -5388,7 +5383,6 @@
     Document* document = frame->frame()->document();
     Element* element = document->getElementById("data");
 
-    webViewHelper.webView()->settings()->setAsynchronousSpellCheckingEnabled(true);
     webViewHelper.webView()->settings()->setUnifiedTextCheckerEnabled(true);
     webViewHelper.webView()->settings()->setEditingBehavior(WebSettings::EditingBehaviorWin);
 
@@ -5410,7 +5404,6 @@
     Document* document = frame->frame()->document();
     Element* element = document->getElementById("data");
 
-    webViewHelper.webView()->settings()->setAsynchronousSpellCheckingEnabled(true);
     webViewHelper.webView()->settings()->setUnifiedTextCheckerEnabled(true);
     webViewHelper.webView()->settings()->setEditingBehavior(WebSettings::EditingBehaviorWin);
 
@@ -5441,7 +5434,6 @@
     Document* document = frame->frame()->document();
     Element* element = document->getElementById("data");
 
-    webViewHelper.webView()->settings()->setAsynchronousSpellCheckingEnabled(true);
     webViewHelper.webView()->settings()->setUnifiedTextCheckerEnabled(true);
     webViewHelper.webView()->settings()->setEditingBehavior(WebSettings::EditingBehaviorWin);
 
diff --git a/third_party/WebKit/Source/web/tests/WebViewTest.cpp b/third_party/WebKit/Source/web/tests/WebViewTest.cpp
index ee1289e9..1c0e36e 100644
--- a/third_party/WebKit/Source/web/tests/WebViewTest.cpp
+++ b/third_party/WebKit/Source/web/tests/WebViewTest.cpp
@@ -1638,6 +1638,39 @@
 }
 #endif
 
+TEST_F(WebViewTest, BlinkCaretOnClosingContextMenu)
+{
+    URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8("form.html"));
+    WebView* webView = m_webViewHelper.initializeAndLoad(m_baseURL + "form.html", true);
+
+    webView->setInitialFocus(false);
+    runPendingTasks();
+
+    // We suspend caret blinking when pressing with mouse right button.
+    // Note that we do not send MouseUp event here since it will be consumed
+    // by the context menu once it shows up.
+    WebMouseEvent mouseEvent;
+    mouseEvent.button = WebMouseEvent::ButtonRight;
+    mouseEvent.x = 1;
+    mouseEvent.y = 1;
+    mouseEvent.clickCount = 1;
+    mouseEvent.type = WebInputEvent::MouseDown;
+    webView->handleInputEvent(mouseEvent);
+    runPendingTasks();
+
+    WebLocalFrameImpl* mainFrame = toWebLocalFrameImpl(webView->mainFrame());
+    EXPECT_TRUE(mainFrame->frame()->selection().isCaretBlinkingSuspended());
+
+    // Caret blinking is still suspended after showing context menu.
+    webView->showContextMenu();
+    EXPECT_TRUE(mainFrame->frame()->selection().isCaretBlinkingSuspended());
+
+    // Caret blinking will be resumed only after context menu is closed.
+    webView->didCloseContextMenu();
+
+    EXPECT_FALSE(mainFrame->frame()->selection().isCaretBlinkingSuspended());
+}
+
 TEST_F(WebViewTest, SelectionOnReadOnlyInput)
 {
     URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8("selection_readonly.html"));
diff --git a/third_party/WebKit/Source/web/tests/data/touch-action-iframe.html b/third_party/WebKit/Source/web/tests/data/touch-action-iframe.html
new file mode 100644
index 0000000..336478a
--- /dev/null
+++ b/third_party/WebKit/Source/web/tests/data/touch-action-iframe.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<link rel='stylesheet' type='text/css' href='touch-action-tests.css'>
+<script src='touch-action-tests.js'></script>
+
+<!-- 
+     Test a bunch of cases involving iframes.
+-->
+<iframe srcdoc="
+  <div style='touch-action: none;' expected-action='none'>
+    touch-action: none still applies inside an iframe
+  </div>
+"></iframe>
+
+<iframe style='touch-action: none;' srcdoc="
+  <div expected-action='pan-x-y'>
+    Zoom (but not scroll) related touch-action bits propagate into iframes
+  </div>
+"></iframe>
+
+<iframe style='touch-action: manipulation;' srcdoc="
+  <div expected-action='manipulation'>
+      touch-action: manipulation is maintained across iframes
+  </div>
+"></iframe>
diff --git a/third_party/WebKit/Source/web/tests/data/touch-action-overflow.html b/third_party/WebKit/Source/web/tests/data/touch-action-overflow.html
index 525aade..ec6f7393 100644
--- a/third_party/WebKit/Source/web/tests/data/touch-action-overflow.html
+++ b/third_party/WebKit/Source/web/tests/data/touch-action-overflow.html
@@ -20,7 +20,13 @@
 </div>
 
 <div class='ta-none'>
-  <div class='scroll' expected-action='auto'>      
-    Touch-action: none is not propagated into overflow-scroll elements
+  <div class='scroll' expected-action='pan-x-y'>
+    Zoom (but not scroll) related touch-action bits propagate into overflow-scroll elements
+  </div>
+</div>
+
+<div class='ta-manipulation'>
+  <div class='scroll' expected-action='manipulation'>
+      touch-action: manipulation is maintained across overflow-scroll elements
   </div>
 </div>
diff --git a/third_party/WebKit/Source/web/tests/data/touch-action-tests.css b/third_party/WebKit/Source/web/tests/data/touch-action-tests.css
index b0c5724..92a3a4b5 100644
--- a/third_party/WebKit/Source/web/tests/data/touch-action-tests.css
+++ b/third_party/WebKit/Source/web/tests/data/touch-action-tests.css
@@ -70,6 +70,11 @@
   overflow: scroll;
   height: 50px;
 }
+iframe {
+  height: 50px;
+  display: block;
+  margin: 5px;
+}
 .spacer {
   height: 500px;
 }
diff --git a/third_party/WebKit/Source/web/web.gypi b/third_party/WebKit/Source/web/web.gypi
index bcbc134..add9ebe6 100644
--- a/third_party/WebKit/Source/web/web.gypi
+++ b/third_party/WebKit/Source/web/web.gypi
@@ -177,6 +177,7 @@
       'WebMediaDevicesRequest.cpp',
       'WebMediaStreamRegistry.cpp',
       'WebMetaElement.cpp',
+      'WebMemoryPressureListener.cpp',
       'WebNetworkStateNotifier.cpp',
       'WebNode.cpp',
       'WebOptionElement.cpp',
@@ -190,8 +191,6 @@
       'WebPluginContainerImpl.cpp',
       'WebPluginContainerImpl.h',
       'WebPluginDocument.cpp',
-      'WebPluginLoadObserver.cpp',
-      'WebPluginLoadObserver.h',
       'WebPluginScriptForbiddenScope.cpp',
       'WebRange.cpp',
       'WebRemoteFrameImpl.cpp',
diff --git a/third_party/WebKit/Source/wtf/AddressSpaceRandomization.cpp b/third_party/WebKit/Source/wtf/AddressSpaceRandomization.cpp
index bad3158..cc00aaa 100644
--- a/third_party/WebKit/Source/wtf/AddressSpaceRandomization.cpp
+++ b/third_party/WebKit/Source/wtf/AddressSpaceRandomization.cpp
@@ -22,7 +22,7 @@
 // This is the same PRNG as used by tcmalloc for mapping address randomness;
 // see http://burtleburtle.net/bob/rand/smallprng.html
 struct ranctx {
-    int lock;
+    SpinLock lock;
     bool initialized;
     uint32_t a;
     uint32_t b;
@@ -46,7 +46,7 @@
 
 uint32_t ranval(ranctx* x)
 {
-    spinLockLock(&x->lock);
+    SpinLock::Guard guard(x->lock);
     if (UNLIKELY(!x->initialized)) {
         x->initialized = true;
         char c;
@@ -73,7 +73,6 @@
         }
     }
     uint32_t ret = ranvalInternal(x);
-    spinLockUnlock(&x->lock);
     return ret;
 }
 
diff --git a/third_party/WebKit/Source/wtf/ContainerAnnotations.h b/third_party/WebKit/Source/wtf/ContainerAnnotations.h
index 9c5fb9e..105515438 100644
--- a/third_party/WebKit/Source/wtf/ContainerAnnotations.h
+++ b/third_party/WebKit/Source/wtf/ContainerAnnotations.h
@@ -5,6 +5,7 @@
 #ifndef WTF_ContainerAnnotations_h
 #define WTF_ContainerAnnotations_h
 
+#include "wtf/AddressSanitizer.h"
 #include "wtf/CPU.h"
 
 // TODO(ochang): Remove the CPU(X86_64) condition to enable this for X86 once
diff --git a/third_party/WebKit/Source/wtf/PartitionAlloc.cpp b/third_party/WebKit/Source/wtf/PartitionAlloc.cpp
index 8e6cdd9..a71dd00 100644
--- a/third_party/WebKit/Source/wtf/PartitionAlloc.cpp
+++ b/third_party/WebKit/Source/wtf/PartitionAlloc.cpp
@@ -55,7 +55,7 @@
 
 namespace WTF {
 
-int PartitionRootBase::gInitializedLock = 0;
+SpinLock PartitionRootBase::gInitializedLock;
 bool PartitionRootBase::gInitialized = false;
 PartitionPage PartitionRootBase::gSeedPage;
 PartitionBucket PartitionRootBase::gPagedBucket;
@@ -104,15 +104,15 @@
 static void partitionAllocBaseInit(PartitionRootBase* root)
 {
     ASSERT(!root->initialized);
-
-    spinLockLock(&PartitionRootBase::gInitializedLock);
-    if (!PartitionRootBase::gInitialized) {
-        PartitionRootBase::gInitialized = true;
-        // We mark the seed page as free to make sure it is skipped by our
-        // logic to find a new active page.
-        PartitionRootBase::gPagedBucket.activePagesHead = &PartitionRootGeneric::gSeedPage;
+    {
+        SpinLock::Guard guard(PartitionRootBase::gInitializedLock);
+        if (!PartitionRootBase::gInitialized) {
+            PartitionRootBase::gInitialized = true;
+            // We mark the seed page as free to make sure it is skipped by our
+            // logic to find a new active page.
+            PartitionRootBase::gPagedBucket.activePagesHead = &PartitionRootGeneric::gSeedPage;
+        }
     }
-    spinLockUnlock(&PartitionRootBase::gInitializedLock);
 
     root->initialized = true;
     root->totalSizeOfCommittedPages = 0;
@@ -166,7 +166,7 @@
 
 void partitionAllocGenericInit(PartitionRootGeneric* root)
 {
-    spinLockLock(&root->lock);
+    SpinLock::Guard guard(root->lock);
 
     partitionAllocBaseInit(root);
 
@@ -243,8 +243,6 @@
     // And there's one last bucket lookup that will be hit for e.g. malloc(-1),
     // which tries to overflow to a non-existant order.
     *bucketPtr = &PartitionRootGeneric::gPagedBucket;
-
-    spinLockUnlock(&root->lock);
 }
 
 static bool partitionAllocShutdownBucket(PartitionBucket* bucket)
@@ -293,7 +291,7 @@
 
 bool partitionAllocGenericShutdown(PartitionRootGeneric* root)
 {
-    spinLockLock(&root->lock);
+    SpinLock::Guard guard(root->lock);
     bool foundLeak = false;
     size_t i;
     for (i = 0; i < kGenericNumBuckets; ++i) {
@@ -301,7 +299,6 @@
         foundLeak |= partitionAllocShutdownBucket(bucket);
     }
     foundLeak |= partitionAllocBaseShutdown(root);
-    spinLockUnlock(&root->lock);
     return !foundLeak;
 }
 
@@ -1241,7 +1238,7 @@
 
 void partitionPurgeMemoryGeneric(PartitionRootGeneric* root, int flags)
 {
-    spinLockLock(&root->lock);
+    SpinLock::Guard guard(root->lock);
     if (flags & PartitionPurgeDecommitEmptyPages)
         partitionDecommitEmptyPages(root);
     if (flags & PartitionPurgeDiscardUnusedSystemPages) {
@@ -1251,7 +1248,6 @@
                 partitionPurgeBucket(bucket);
         }
     }
-    spinLockUnlock(&root->lock);
 }
 
 static void partitionDumpPageStats(PartitionBucketMemoryStats* statsOut, const PartitionPage* page)
@@ -1329,29 +1325,29 @@
     uint32_t directMapLengths[kMaxReportableDirectMaps];
     size_t numDirectMappedAllocations = 0;
 
-    spinLockLock(&partition->lock);
+    {
+        SpinLock::Guard guard(partition->lock);
 
-    for (size_t i = 0; i < kGenericNumBuckets; ++i) {
-        const PartitionBucket* bucket = &partition->buckets[i];
-        // Don't report the pseudo buckets that the generic allocator sets up in
-        // order to preserve a fast size->bucket map (see
-        // partitionAllocGenericInit for details).
-        if (!bucket->activePagesHead)
-            bucketStats[i].isValid = false;
-        else
-            partitionDumpBucketStats(&bucketStats[i], bucket);
+        for (size_t i = 0; i < kGenericNumBuckets; ++i) {
+            const PartitionBucket* bucket = &partition->buckets[i];
+            // Don't report the pseudo buckets that the generic allocator sets up in
+            // order to preserve a fast size->bucket map (see
+            // partitionAllocGenericInit for details).
+            if (!bucket->activePagesHead)
+                bucketStats[i].isValid = false;
+            else
+                partitionDumpBucketStats(&bucketStats[i], bucket);
+        }
+
+        for (PartitionDirectMapExtent* extent = partition->directMapList; extent; extent = extent->nextExtent) {
+            ASSERT(!extent->nextExtent || extent->nextExtent->prevExtent == extent);
+            directMapLengths[numDirectMappedAllocations] = extent->bucket->slotSize;
+            ++numDirectMappedAllocations;
+            if (numDirectMappedAllocations == kMaxReportableDirectMaps)
+                break;
+        }
     }
 
-    for (PartitionDirectMapExtent* extent = partition->directMapList; extent; extent = extent->nextExtent) {
-        ASSERT(!extent->nextExtent || extent->nextExtent->prevExtent == extent);
-        directMapLengths[numDirectMappedAllocations] = extent->bucket->slotSize;
-        ++numDirectMappedAllocations;
-        if (numDirectMappedAllocations == kMaxReportableDirectMaps)
-            break;
-    }
-
-    spinLockUnlock(&partition->lock);
-
     // partitionsDumpBucketStats is called after collecting stats because it
     // can try to allocate using PartitionAllocGeneric and it can't obtain the
     // lock.
diff --git a/third_party/WebKit/Source/wtf/PartitionAlloc.h b/third_party/WebKit/Source/wtf/PartitionAlloc.h
index 1dba60909..2f2d82158 100644
--- a/third_party/WebKit/Source/wtf/PartitionAlloc.h
+++ b/third_party/WebKit/Source/wtf/PartitionAlloc.h
@@ -309,7 +309,7 @@
     int16_t globalEmptyPageRingIndex;
     uintptr_t invertedSelf;
 
-    static int gInitializedLock;
+    static SpinLock gInitializedLock;
     static bool gInitialized;
     // gSeedPage is used as a sentinel to indicate that there is no page
     // in the active page list. We can use nullptr, but in that case we need
@@ -330,7 +330,7 @@
 
 // Never instantiate a PartitionRootGeneric directly, instead use PartitionAllocatorGeneric.
 struct PartitionRootGeneric : public PartitionRootBase {
-    int lock;
+    SpinLock lock;
     // Some pre-computed constants.
     size_t orderIndexShifts[kBitsPerSizet + 1];
     size_t orderSubIndexMasks[kBitsPerSizet + 1];
@@ -752,16 +752,18 @@
     size_t requestedSize = size;
     size = partitionCookieSizeAdjustAdd(size);
     PartitionBucket* bucket = partitionGenericSizeToBucket(root, size);
-    spinLockLock(&root->lock);
-    // TODO(bashi): Remove following RELEAE_ASSERT()s once we find the cause of
-    // http://crbug.com/514141
+    void* ret = nullptr;
+    {
+        SpinLock::Guard guard(root->lock);
+        // TODO(bashi): Remove following RELEAE_ASSERT()s once we find the cause of
+        // http://crbug.com/514141
 #if OS(ANDROID)
-    RELEASE_ASSERT(bucket >= &root->buckets[0] || bucket == &PartitionRootGeneric::gPagedBucket);
-    RELEASE_ASSERT(bucket <= &root->buckets[kGenericNumBuckets - 1] || bucket == &PartitionRootGeneric::gPagedBucket);
-    RELEASE_ASSERT(root->initialized);
+        RELEASE_ASSERT(bucket >= &root->buckets[0] || bucket == &PartitionRootGeneric::gPagedBucket);
+        RELEASE_ASSERT(bucket <= &root->buckets[kGenericNumBuckets - 1] || bucket == &PartitionRootGeneric::gPagedBucket);
+        RELEASE_ASSERT(root->initialized);
 #endif
-    void* ret = partitionBucketAlloc(root, flags, size, bucket);
-    spinLockUnlock(&root->lock);
+        ret = partitionBucketAlloc(root, flags, size, bucket);
+    }
     PartitionAllocHooks::allocationHookIfEnabled(ret, requestedSize, typeName);
     return ret;
 #endif
@@ -786,9 +788,10 @@
     ptr = partitionCookieFreePointerAdjust(ptr);
     ASSERT(partitionPointerIsValid(ptr));
     PartitionPage* page = partitionPointerToPage(ptr);
-    spinLockLock(&root->lock);
-    partitionFreeWithPage(ptr, page);
-    spinLockUnlock(&root->lock);
+    {
+        SpinLock::Guard guard(root->lock);
+        partitionFreeWithPage(ptr, page);
+    }
 #endif
 }
 
diff --git a/third_party/WebKit/Source/wtf/Partitions.cpp b/third_party/WebKit/Source/wtf/Partitions.cpp
index 39914b4..2e97e011 100644
--- a/third_party/WebKit/Source/wtf/Partitions.cpp
+++ b/third_party/WebKit/Source/wtf/Partitions.cpp
@@ -39,7 +39,7 @@
 
 const char* const Partitions::kAllocatedObjectPoolName = "partition_alloc/allocated_objects";
 
-int Partitions::s_initializationLock = 0;
+SpinLock Partitions::s_initializationLock;
 bool Partitions::s_initialized = false;
 
 PartitionAllocatorGeneric Partitions::m_fastMallocAllocator;
@@ -50,7 +50,7 @@
 
 void Partitions::initialize(HistogramEnumerationFunction histogramEnumeration)
 {
-    spinLockLock(&s_initializationLock);
+    SpinLock::Guard guard(s_initializationLock);
 
     if (!s_initialized) {
         partitionAllocGlobalInit(&Partitions::handleOutOfMemory);
@@ -61,13 +61,11 @@
         m_histogramEnumeration = histogramEnumeration;
         s_initialized = true;
     }
-
-    spinLockUnlock(&s_initializationLock);
 }
 
 void Partitions::shutdown()
 {
-    spinLockLock(&s_initializationLock);
+    SpinLock::Guard guard(s_initializationLock);
 
     // We could ASSERT here for a memory leak within the partition, but it leads
     // to very hard to diagnose ASSERTs, so it's best to leave leak checking for
@@ -78,8 +76,6 @@
         (void) m_bufferAllocator.shutdown();
         (void) m_fastMallocAllocator.shutdown();
     }
-
-    spinLockUnlock(&s_initializationLock);
 }
 
 void Partitions::decommitFreeableMemory()
diff --git a/third_party/WebKit/Source/wtf/Partitions.h b/third_party/WebKit/Source/wtf/Partitions.h
index 7b18ef8..5651c2b8 100644
--- a/third_party/WebKit/Source/wtf/Partitions.h
+++ b/third_party/WebKit/Source/wtf/Partitions.h
@@ -125,7 +125,7 @@
     static void handleOutOfMemory();
 
 private:
-    static int s_initializationLock;
+    static SpinLock s_initializationLock;
     static bool s_initialized;
 
     // We have the following four partitions.
diff --git a/third_party/WebKit/Source/wtf/SpinLock.cpp b/third_party/WebKit/Source/wtf/SpinLock.cpp
index 542f97be..c85203b 100644
--- a/third_party/WebKit/Source/wtf/SpinLock.cpp
+++ b/third_party/WebKit/Source/wtf/SpinLock.cpp
@@ -53,7 +53,7 @@
 
 namespace WTF {
 
-void slowSpinLockLock(int volatile* lock)
+void SpinLock::lockSlow()
 {
     // The value of kYieldProcessorTries is cargo culted from TCMalloc, Windows
     // critical section defaults, and various other recommendations.
@@ -64,14 +64,14 @@
             for (int count = 0; count < kYieldProcessorTries; ++count) {
                 // Let the Processor know we're spinning.
                 YIELD_PROCESSOR;
-                if (!*lock && LIKELY(!atomicTestAndSetToOne(lock)))
+                if (!m_lock.load(std::memory_order_relaxed) && LIKELY(!m_lock.exchange(true, std::memory_order_acq_rel)))
                     return;
             }
 
             // Give the OS a chance to schedule something on this core.
             YIELD_THREAD;
-        } while (*lock);
-    } while (UNLIKELY(atomicTestAndSetToOne(lock)));
+        } while (m_lock.load(std::memory_order_relaxed));
+    } while (UNLIKELY(m_lock.exchange(true, std::memory_order_acq_rel)));
 }
 
 } // namespace WTF
diff --git a/third_party/WebKit/Source/wtf/SpinLock.h b/third_party/WebKit/Source/wtf/SpinLock.h
index 08724a3..b8d6b9c 100644
--- a/third_party/WebKit/Source/wtf/SpinLock.h
+++ b/third_party/WebKit/Source/wtf/SpinLock.h
@@ -31,36 +31,48 @@
 #ifndef WTF_SpinLock_h
 #define WTF_SpinLock_h
 
-// DESCRIPTION
-// spinLockLock() and spinLockUnlock() are simple spinlock primitives based on
-// the standard CPU primitive of atomic increment and decrement of an int at
-// a given memory address. These are intended only for very short duration locks
-// and assume a system with multiple cores. For any potentially longer wait you
-// should be using a real lock.
+#include "wtf/Compiler.h"
+#include "wtf/WTFExport.h"
+#include <atomic>
+#include <memory>
+#include <mutex>
 
-#include "wtf/Atomics.h"
+// DESCRIPTION
+// Spinlock is a simple spinlock class based on the standard CPU primitive of
+// atomic increment and decrement of an int at a given memory address. These are
+// intended only for very short duration locks and assume a system with multiple
+// cores. For any potentially longer wait you should be using a real lock.
 
 namespace WTF {
 
-// This is called if the initial attempt to acquire the lock fails. It's a bit
-// slower, but has a much better scheduling and power consumption behavior.
-WTF_EXPORT void slowSpinLockLock(int volatile* lock);
+class SpinLock {
+public:
+    using Guard = std::lock_guard<SpinLock>;
 
-ALWAYS_INLINE void spinLockLock(int volatile* lock)
-{
-    if (LIKELY(!atomicTestAndSetToOne(lock)))
-        return;
-    slowSpinLockLock(lock);
-}
+    ALWAYS_INLINE void lock()
+    {
+        static_assert(sizeof(m_lock) == sizeof(int), "int and m_lock are different sizes");
+        if (LIKELY(!m_lock.exchange(true, std::memory_order_acq_rel)))
+            return;
+        lockSlow();
+    }
 
-ALWAYS_INLINE void spinLockUnlock(int volatile* lock)
-{
-    atomicSetOneToZero(lock);
-}
+    ALWAYS_INLINE void unlock()
+    {
+        m_lock.store(false, std::memory_order_release);
+    }
+
+private:
+    // This is called if the initial attempt to acquire the lock fails. It's
+    // slower, but has a much better scheduling and power consumption behavior.
+    WTF_EXPORT void lockSlow();
+
+    std::atomic<int> m_lock;
+};
+
 
 } // namespace WTF
 
-using WTF::spinLockLock;
-using WTF::spinLockUnlock;
+using WTF::SpinLock;
 
 #endif // WTF_SpinLock_h
diff --git a/third_party/WebKit/Source/wtf/text/TextEncodingRegistry.cpp b/third_party/WebKit/Source/wtf/text/TextEncodingRegistry.cpp
index 73c38d9f..d49195e 100644
--- a/third_party/WebKit/Source/wtf/text/TextEncodingRegistry.cpp
+++ b/third_party/WebKit/Source/wtf/text/TextEncodingRegistry.cpp
@@ -28,6 +28,7 @@
 #include "wtf/text/TextEncodingRegistry.h"
 
 #include "wtf/ASCIICType.h"
+#include "wtf/Atomics.h"
 #include "wtf/CurrentTime.h"
 #include "wtf/HashMap.h"
 #include "wtf/HashSet.h"
diff --git a/third_party/WebKit/public/blink_headers.gypi b/third_party/WebKit/public/blink_headers.gypi
index fb89da1..612a396 100644
--- a/third_party/WebKit/public/blink_headers.gypi
+++ b/third_party/WebKit/public/blink_headers.gypi
@@ -418,6 +418,7 @@
       "web/WebMediaDevicesRequest.h",
       "web/WebMediaPlayerAction.h",
       "web/WebMediaStreamRegistry.h",
+      "web/WebMemoryPressureListener.h",
       "web/WebMenuItemInfo.h",
       "web/WebMetaElement.h",
       "web/WebNavigationPolicy.h",
diff --git a/third_party/WebKit/public/platform/WebMediaConstraints.h b/third_party/WebKit/public/platform/WebMediaConstraints.h
index 82ccbf41..da3380e8 100644
--- a/third_party/WebKit/public/platform/WebMediaConstraints.h
+++ b/third_party/WebKit/public/platform/WebMediaConstraints.h
@@ -73,6 +73,7 @@
     BLINK_PLATFORM_EXPORT void reset();
     bool isNull() const { return m_private.isNull(); }
 
+    BLINK_PLATFORM_EXPORT bool isEmpty() const;
     BLINK_PLATFORM_EXPORT void getOptionalConstraints(WebVector<WebMediaConstraint>&) const;
     BLINK_PLATFORM_EXPORT void getMandatoryConstraints(WebVector<WebMediaConstraint>&) const;
 
diff --git a/third_party/WebKit/public/web/WebCache.h b/third_party/WebKit/public/web/WebCache.h
index 8f4a619..7ea39c9 100644
--- a/third_party/WebKit/public/web/WebCache.h
+++ b/third_party/WebKit/public/web/WebCache.h
@@ -84,10 +84,6 @@
     // Get usage stats about the resource cache.
     BLINK_EXPORT static void getResourceTypeStats(ResourceTypeStats*);
 
-    // Prunes all resources (as much as possible; some resources may not be
-    // cleared if they are actively referenced). And releases cache memory.
-    BLINK_EXPORT static void pruneAll();
-
 private:
     WebCache();  // Not intended to be instanced.
 };
diff --git a/third_party/WebKit/public/web/WebFrame.h b/third_party/WebKit/public/web/WebFrame.h
index c99c667..176df40c 100644
--- a/third_party/WebKit/public/web/WebFrame.h
+++ b/third_party/WebKit/public/web/WebFrame.h
@@ -744,10 +744,6 @@
     WebPrivateOwnPtr<OpenedFrameTracker> m_openedFrameTracker;
 };
 
-#if BLINK_IMPLEMENTATION
-Frame* toCoreFrame(const WebFrame*);
-#endif
-
 } // namespace blink
 
 #endif
diff --git a/third_party/WebKit/public/web/WebFrameClient.h b/third_party/WebKit/public/web/WebFrameClient.h
index d51e8210..89f2cef 100644
--- a/third_party/WebKit/public/web/WebFrameClient.h
+++ b/third_party/WebKit/public/web/WebFrameClient.h
@@ -460,9 +460,6 @@
     // A performance timing event (e.g. first paint) occurred
     virtual void didChangePerformanceTiming() { }
 
-    // The loaders in this frame have been stopped.
-    virtual void didAbortLoading(WebLocalFrame*) { }
-
 
     // Script notifications ------------------------------------------------
 
diff --git a/third_party/WebKit/public/web/WebMemoryPressureListener.h b/third_party/WebKit/public/web/WebMemoryPressureListener.h
new file mode 100644
index 0000000..c1cbdd3
--- /dev/null
+++ b/third_party/WebKit/public/web/WebMemoryPressureListener.h
@@ -0,0 +1,20 @@
+// 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.
+
+#ifndef WebMemoryPressureListener_h
+#define WebMemoryPressureListener_h
+
+#include "public/platform/WebCommon.h"
+
+namespace blink {
+
+class WebMemoryPressureListener {
+public:
+    // Called when a memory pressure notification is received.
+    BLINK_EXPORT static void onMemoryPressure();
+};
+
+} // namespace blink
+
+#endif
diff --git a/third_party/WebKit/public/web/WebPlugin.h b/third_party/WebKit/public/web/WebPlugin.h
index 0d979f46..dfeefbf7 100644
--- a/third_party/WebKit/public/web/WebPlugin.h
+++ b/third_party/WebKit/public/web/WebPlugin.h
@@ -118,12 +118,6 @@
     virtual void didFinishLoading() = 0;
     virtual void didFailLoading(const WebURLError&) = 0;
 
-    // Called in response to WebPluginContainer::loadFrameRequest
-    virtual void didFinishLoadingFrameRequest(
-        const WebURL&, void* notifyData) = 0;
-    virtual void didFailLoadingFrameRequest(
-        const WebURL&, void* notifyData, const WebURLError&) = 0;
-
     // Printing interface.
     // Whether the plugin supports its own paginated print. The other print
     // interface methods are called only if this method returns true.
diff --git a/third_party/WebKit/public/web/WebPluginContainer.h b/third_party/WebKit/public/web/WebPluginContainer.h
index b757702..46edc00 100644
--- a/third_party/WebKit/public/web/WebPluginContainer.h
+++ b/third_party/WebKit/public/web/WebPluginContainer.h
@@ -106,7 +106,7 @@
     // called if the load failed.  The given notifyData is passed along to
     // the callback.
     virtual void loadFrameRequest(
-        const WebURLRequest&, const WebString& target, bool notifyNeeded, void* notifyData) = 0;
+        const WebURLRequest&, const WebString& target) = 0;
 
     // Determines whether the given rectangle in this plugin is above all other
     // content. The rectangle is in the plugin's coordinate system.
diff --git a/third_party/WebKit/public/web/WebRemoteFrameClient.h b/third_party/WebKit/public/web/WebRemoteFrameClient.h
index 703943b..5a6a8248 100644
--- a/third_party/WebKit/public/web/WebRemoteFrameClient.h
+++ b/third_party/WebKit/public/web/WebRemoteFrameClient.h
@@ -5,6 +5,7 @@
 #ifndef WebRemoteFrameClient_h
 #define WebRemoteFrameClient_h
 
+#include "public/platform/WebFocusType.h"
 #include "public/platform/WebSecurityOrigin.h"
 #include "public/web/WebDOMMessageEvent.h"
 
@@ -48,6 +49,11 @@
 
     // This frame updated its opener to another frame.
     virtual void didChangeOpener(WebFrame* opener) { }
+
+    // Continue sequential focus navigation in this frame.  This is called when
+    // the |source| frame is searching for the next focusable element (e.g., in
+    // response to <tab>) and encounters a remote frame.
+    virtual void advanceFocus(WebFocusType type, WebLocalFrame* source) { }
 };
 
 } // namespace blink
diff --git a/third_party/WebKit/public/web/WebSettings.h b/third_party/WebKit/public/web/WebSettings.h
index 93af9d1d..270b0cbe 100644
--- a/third_party/WebKit/public/web/WebSettings.h
+++ b/third_party/WebKit/public/web/WebSettings.h
@@ -119,7 +119,6 @@
     virtual void setAllowUniversalAccessFromFileURLs(bool) = 0;
     virtual void setAntialiased2dCanvasEnabled(bool) = 0;
     virtual void setAntialiasedClips2dCanvasEnabled(bool) = 0;
-    virtual void setAsynchronousSpellCheckingEnabled(bool) = 0;
     virtual void setAutoplayExperimentMode(const WebString&) = 0;
     virtual void setAutoZoomFocusedNodeToLegibleScale(bool) = 0;
     virtual void setCaretBrowsingEnabled(bool) = 0;
diff --git a/third_party/WebKit/public/web/WebView.h b/third_party/WebKit/public/web/WebView.h
index 7a8867ca..843f6339 100644
--- a/third_party/WebKit/public/web/WebView.h
+++ b/third_party/WebKit/public/web/WebView.h
@@ -33,6 +33,7 @@
 
 #include "../platform/WebColor.h"
 #include "../platform/WebDisplayMode.h"
+#include "../platform/WebFocusType.h"
 #include "../platform/WebPageVisibilityState.h"
 #include "../platform/WebString.h"
 #include "../platform/WebVector.h"
@@ -50,9 +51,11 @@
 class WebDragData;
 class WebFrame;
 class WebHitTestResult;
+class WebLocalFrame;
 class WebPageImportanceSignals;
 class WebPageOverlay;
 class WebPrerendererClient;
+class WebRemoteFrame;
 class WebSettings;
 class WebSpellCheckClient;
 class WebString;
@@ -191,6 +194,11 @@
     // previous element in the tab sequence (if reverse is true).
     virtual void advanceFocus(bool reverse) { }
 
+    // Advance the focus from the frame |from| to the next in sequence
+    // (determined by WebFocusType) focusable element in frame |to|. Used when
+    // focus needs to advance to/from a cross-process frame.
+    virtual void advanceFocusAcrossFrames(WebFocusType, WebRemoteFrame* from, WebLocalFrame* to) { }
+
     // Animate a scale into the specified rect where multiple targets were
     // found from previous tap gesture.
     // Returns false if it doesn't do any zooming.
@@ -391,6 +399,9 @@
     // Shows a context menu for the currently focused element.
     virtual void showContextMenu() = 0;
 
+    // Notify that context menu has been closed.
+    virtual void didCloseContextMenu() = 0;
+
 
     // SmartClip support ---------------------------------------------------
     virtual void extractSmartClipData(WebRect initRect, WebString& text, WebString& html, WebRect& resultRect) = 0;
diff --git a/third_party/boringssl/linux-x86_64/crypto/bn/x86_64-mont5.S b/third_party/boringssl/linux-x86_64/crypto/bn/x86_64-mont5.S
index 02edc69b..214064e6 100644
--- a/third_party/boringssl/linux-x86_64/crypto/bn/x86_64-mont5.S
+++ b/third_party/boringssl/linux-x86_64/crypto/bn/x86_64-mont5.S
@@ -1561,6 +1561,15 @@
 .align	32
 .L8x_tail_done:
 	addq	(%rdx),%r8
+	adcq	$0,%r9
+	adcq	$0,%r10
+	adcq	$0,%r11
+	adcq	$0,%r12
+	adcq	$0,%r13
+	adcq	$0,%r14
+	adcq	$0,%r15
+
+
 	xorq	%rax,%rax
 
 	negq	%rsi
diff --git a/third_party/boringssl/linux-x86_64/crypto/ec/p256-x86_64-asm.S b/third_party/boringssl/linux-x86_64/crypto/ec/p256-x86_64-asm.S
index db00544c..2884c69b 100644
--- a/third_party/boringssl/linux-x86_64/crypto/ec/p256-x86_64-asm.S
+++ b/third_party/boringssl/linux-x86_64/crypto/ec/p256-x86_64-asm.S
@@ -8,10 +8,6 @@
 .Lpoly:
 .quad	0xffffffffffffffff, 0x00000000ffffffff, 0x0000000000000000, 0xffffffff00000001
 
-
-.LRR:
-.quad	0x0000000000000003, 0xfffffffbffffffff, 0xfffffffffffffffe, 0x00000004fffffffd
-
 .LOne:
 .long	1,1,1,1,1,1,1,1
 .LTwo:
@@ -21,8 +17,6 @@
 .LONE_mont:
 .quad	0x0000000000000001, 0xffffffff00000000, 0xffffffffffffffff, 0x00000000fffffffe
 
-.globl	ecp_nistz256_mul_by_2
-.hidden ecp_nistz256_mul_by_2
 .type	ecp_nistz256_mul_by_2,@function
 .align	64
 ecp_nistz256_mul_by_2:
@@ -66,228 +60,6 @@
 
 
 
-.globl	ecp_nistz256_div_by_2
-.hidden ecp_nistz256_div_by_2
-.type	ecp_nistz256_div_by_2,@function
-.align	32
-ecp_nistz256_div_by_2:
-	pushq	%r12
-	pushq	%r13
-
-	movq	0(%rsi),%r8
-	movq	8(%rsi),%r9
-	movq	16(%rsi),%r10
-	movq	%r8,%rax
-	movq	24(%rsi),%r11
-	leaq	.Lpoly(%rip),%rsi
-
-	movq	%r9,%rdx
-	xorq	%r13,%r13
-	addq	0(%rsi),%r8
-	movq	%r10,%rcx
-	adcq	8(%rsi),%r9
-	adcq	16(%rsi),%r10
-	movq	%r11,%r12
-	adcq	24(%rsi),%r11
-	adcq	$0,%r13
-	xorq	%rsi,%rsi
-	testq	$1,%rax
-
-	cmovzq	%rax,%r8
-	cmovzq	%rdx,%r9
-	cmovzq	%rcx,%r10
-	cmovzq	%r12,%r11
-	cmovzq	%rsi,%r13
-
-	movq	%r9,%rax
-	shrq	$1,%r8
-	shlq	$63,%rax
-	movq	%r10,%rdx
-	shrq	$1,%r9
-	orq	%rax,%r8
-	shlq	$63,%rdx
-	movq	%r11,%rcx
-	shrq	$1,%r10
-	orq	%rdx,%r9
-	shlq	$63,%rcx
-	shrq	$1,%r11
-	shlq	$63,%r13
-	orq	%rcx,%r10
-	orq	%r13,%r11
-
-	movq	%r8,0(%rdi)
-	movq	%r9,8(%rdi)
-	movq	%r10,16(%rdi)
-	movq	%r11,24(%rdi)
-
-	popq	%r13
-	popq	%r12
-	.byte	0xf3,0xc3
-.size	ecp_nistz256_div_by_2,.-ecp_nistz256_div_by_2
-
-
-
-.globl	ecp_nistz256_mul_by_3
-.hidden ecp_nistz256_mul_by_3
-.type	ecp_nistz256_mul_by_3,@function
-.align	32
-ecp_nistz256_mul_by_3:
-	pushq	%r12
-	pushq	%r13
-
-	movq	0(%rsi),%r8
-	xorq	%r13,%r13
-	movq	8(%rsi),%r9
-	addq	%r8,%r8
-	movq	16(%rsi),%r10
-	adcq	%r9,%r9
-	movq	24(%rsi),%r11
-	movq	%r8,%rax
-	adcq	%r10,%r10
-	adcq	%r11,%r11
-	movq	%r9,%rdx
-	adcq	$0,%r13
-
-	subq	$-1,%r8
-	movq	%r10,%rcx
-	sbbq	.Lpoly+8(%rip),%r9
-	sbbq	$0,%r10
-	movq	%r11,%r12
-	sbbq	.Lpoly+24(%rip),%r11
-	testq	%r13,%r13
-
-	cmovzq	%rax,%r8
-	cmovzq	%rdx,%r9
-	cmovzq	%rcx,%r10
-	cmovzq	%r12,%r11
-
-	xorq	%r13,%r13
-	addq	0(%rsi),%r8
-	adcq	8(%rsi),%r9
-	movq	%r8,%rax
-	adcq	16(%rsi),%r10
-	adcq	24(%rsi),%r11
-	movq	%r9,%rdx
-	adcq	$0,%r13
-
-	subq	$-1,%r8
-	movq	%r10,%rcx
-	sbbq	.Lpoly+8(%rip),%r9
-	sbbq	$0,%r10
-	movq	%r11,%r12
-	sbbq	.Lpoly+24(%rip),%r11
-	testq	%r13,%r13
-
-	cmovzq	%rax,%r8
-	cmovzq	%rdx,%r9
-	movq	%r8,0(%rdi)
-	cmovzq	%rcx,%r10
-	movq	%r9,8(%rdi)
-	cmovzq	%r12,%r11
-	movq	%r10,16(%rdi)
-	movq	%r11,24(%rdi)
-
-	popq	%r13
-	popq	%r12
-	.byte	0xf3,0xc3
-.size	ecp_nistz256_mul_by_3,.-ecp_nistz256_mul_by_3
-
-
-
-.globl	ecp_nistz256_add
-.hidden ecp_nistz256_add
-.type	ecp_nistz256_add,@function
-.align	32
-ecp_nistz256_add:
-	pushq	%r12
-	pushq	%r13
-
-	movq	0(%rsi),%r8
-	xorq	%r13,%r13
-	movq	8(%rsi),%r9
-	movq	16(%rsi),%r10
-	movq	24(%rsi),%r11
-	leaq	.Lpoly(%rip),%rsi
-
-	addq	0(%rdx),%r8
-	adcq	8(%rdx),%r9
-	movq	%r8,%rax
-	adcq	16(%rdx),%r10
-	adcq	24(%rdx),%r11
-	movq	%r9,%rdx
-	adcq	$0,%r13
-
-	subq	0(%rsi),%r8
-	movq	%r10,%rcx
-	sbbq	8(%rsi),%r9
-	sbbq	16(%rsi),%r10
-	movq	%r11,%r12
-	sbbq	24(%rsi),%r11
-	testq	%r13,%r13
-
-	cmovzq	%rax,%r8
-	cmovzq	%rdx,%r9
-	movq	%r8,0(%rdi)
-	cmovzq	%rcx,%r10
-	movq	%r9,8(%rdi)
-	cmovzq	%r12,%r11
-	movq	%r10,16(%rdi)
-	movq	%r11,24(%rdi)
-
-	popq	%r13
-	popq	%r12
-	.byte	0xf3,0xc3
-.size	ecp_nistz256_add,.-ecp_nistz256_add
-
-
-
-.globl	ecp_nistz256_sub
-.hidden ecp_nistz256_sub
-.type	ecp_nistz256_sub,@function
-.align	32
-ecp_nistz256_sub:
-	pushq	%r12
-	pushq	%r13
-
-	movq	0(%rsi),%r8
-	xorq	%r13,%r13
-	movq	8(%rsi),%r9
-	movq	16(%rsi),%r10
-	movq	24(%rsi),%r11
-	leaq	.Lpoly(%rip),%rsi
-
-	subq	0(%rdx),%r8
-	sbbq	8(%rdx),%r9
-	movq	%r8,%rax
-	sbbq	16(%rdx),%r10
-	sbbq	24(%rdx),%r11
-	movq	%r9,%rdx
-	sbbq	$0,%r13
-
-	addq	0(%rsi),%r8
-	movq	%r10,%rcx
-	adcq	8(%rsi),%r9
-	adcq	16(%rsi),%r10
-	movq	%r11,%r12
-	adcq	24(%rsi),%r11
-	testq	%r13,%r13
-
-	cmovzq	%rax,%r8
-	cmovzq	%rdx,%r9
-	movq	%r8,0(%rdi)
-	cmovzq	%rcx,%r10
-	movq	%r9,8(%rdi)
-	cmovzq	%r12,%r11
-	movq	%r10,16(%rdi)
-	movq	%r11,24(%rdi)
-
-	popq	%r13
-	popq	%r12
-	.byte	0xf3,0xc3
-.size	ecp_nistz256_sub,.-ecp_nistz256_sub
-
-
-
 .globl	ecp_nistz256_neg
 .hidden ecp_nistz256_neg
 .type	ecp_nistz256_neg,@function
@@ -336,19 +108,6 @@
 
 
 
-.globl	ecp_nistz256_to_mont
-.hidden ecp_nistz256_to_mont
-.type	ecp_nistz256_to_mont,@function
-.align	32
-ecp_nistz256_to_mont:
-	leaq	.LRR(%rip),%rdx
-	jmp	.Lmul_mont
-.size	ecp_nistz256_to_mont,.-ecp_nistz256_to_mont
-
-
-
-
-
 
 
 .globl	ecp_nistz256_mul_mont
diff --git a/third_party/boringssl/mac-x86_64/crypto/bn/x86_64-mont5.S b/third_party/boringssl/mac-x86_64/crypto/bn/x86_64-mont5.S
index 2e8f469c..461bfb2 100644
--- a/third_party/boringssl/mac-x86_64/crypto/bn/x86_64-mont5.S
+++ b/third_party/boringssl/mac-x86_64/crypto/bn/x86_64-mont5.S
@@ -1560,6 +1560,15 @@
 .p2align	5
 L$8x_tail_done:
 	addq	(%rdx),%r8
+	adcq	$0,%r9
+	adcq	$0,%r10
+	adcq	$0,%r11
+	adcq	$0,%r12
+	adcq	$0,%r13
+	adcq	$0,%r14
+	adcq	$0,%r15
+
+
 	xorq	%rax,%rax
 
 	negq	%rsi
diff --git a/third_party/boringssl/mac-x86_64/crypto/ec/p256-x86_64-asm.S b/third_party/boringssl/mac-x86_64/crypto/ec/p256-x86_64-asm.S
index 43f7dff..bed1130 100644
--- a/third_party/boringssl/mac-x86_64/crypto/ec/p256-x86_64-asm.S
+++ b/third_party/boringssl/mac-x86_64/crypto/ec/p256-x86_64-asm.S
@@ -7,10 +7,6 @@
 L$poly:
 .quad	0xffffffffffffffff, 0x00000000ffffffff, 0x0000000000000000, 0xffffffff00000001
 
-
-L$RR:
-.quad	0x0000000000000003, 0xfffffffbffffffff, 0xfffffffffffffffe, 0x00000004fffffffd
-
 L$One:
 .long	1,1,1,1,1,1,1,1
 L$Two:
@@ -20,11 +16,9 @@
 L$ONE_mont:
 .quad	0x0000000000000001, 0xffffffff00000000, 0xffffffffffffffff, 0x00000000fffffffe
 
-.globl	_ecp_nistz256_mul_by_2
-.private_extern _ecp_nistz256_mul_by_2
 
 .p2align	6
-_ecp_nistz256_mul_by_2:
+ecp_nistz256_mul_by_2:
 	pushq	%r12
 	pushq	%r13
 
@@ -65,228 +59,6 @@
 
 
 
-.globl	_ecp_nistz256_div_by_2
-.private_extern _ecp_nistz256_div_by_2
-
-.p2align	5
-_ecp_nistz256_div_by_2:
-	pushq	%r12
-	pushq	%r13
-
-	movq	0(%rsi),%r8
-	movq	8(%rsi),%r9
-	movq	16(%rsi),%r10
-	movq	%r8,%rax
-	movq	24(%rsi),%r11
-	leaq	L$poly(%rip),%rsi
-
-	movq	%r9,%rdx
-	xorq	%r13,%r13
-	addq	0(%rsi),%r8
-	movq	%r10,%rcx
-	adcq	8(%rsi),%r9
-	adcq	16(%rsi),%r10
-	movq	%r11,%r12
-	adcq	24(%rsi),%r11
-	adcq	$0,%r13
-	xorq	%rsi,%rsi
-	testq	$1,%rax
-
-	cmovzq	%rax,%r8
-	cmovzq	%rdx,%r9
-	cmovzq	%rcx,%r10
-	cmovzq	%r12,%r11
-	cmovzq	%rsi,%r13
-
-	movq	%r9,%rax
-	shrq	$1,%r8
-	shlq	$63,%rax
-	movq	%r10,%rdx
-	shrq	$1,%r9
-	orq	%rax,%r8
-	shlq	$63,%rdx
-	movq	%r11,%rcx
-	shrq	$1,%r10
-	orq	%rdx,%r9
-	shlq	$63,%rcx
-	shrq	$1,%r11
-	shlq	$63,%r13
-	orq	%rcx,%r10
-	orq	%r13,%r11
-
-	movq	%r8,0(%rdi)
-	movq	%r9,8(%rdi)
-	movq	%r10,16(%rdi)
-	movq	%r11,24(%rdi)
-
-	popq	%r13
-	popq	%r12
-	.byte	0xf3,0xc3
-
-
-
-
-.globl	_ecp_nistz256_mul_by_3
-.private_extern _ecp_nistz256_mul_by_3
-
-.p2align	5
-_ecp_nistz256_mul_by_3:
-	pushq	%r12
-	pushq	%r13
-
-	movq	0(%rsi),%r8
-	xorq	%r13,%r13
-	movq	8(%rsi),%r9
-	addq	%r8,%r8
-	movq	16(%rsi),%r10
-	adcq	%r9,%r9
-	movq	24(%rsi),%r11
-	movq	%r8,%rax
-	adcq	%r10,%r10
-	adcq	%r11,%r11
-	movq	%r9,%rdx
-	adcq	$0,%r13
-
-	subq	$-1,%r8
-	movq	%r10,%rcx
-	sbbq	L$poly+8(%rip),%r9
-	sbbq	$0,%r10
-	movq	%r11,%r12
-	sbbq	L$poly+24(%rip),%r11
-	testq	%r13,%r13
-
-	cmovzq	%rax,%r8
-	cmovzq	%rdx,%r9
-	cmovzq	%rcx,%r10
-	cmovzq	%r12,%r11
-
-	xorq	%r13,%r13
-	addq	0(%rsi),%r8
-	adcq	8(%rsi),%r9
-	movq	%r8,%rax
-	adcq	16(%rsi),%r10
-	adcq	24(%rsi),%r11
-	movq	%r9,%rdx
-	adcq	$0,%r13
-
-	subq	$-1,%r8
-	movq	%r10,%rcx
-	sbbq	L$poly+8(%rip),%r9
-	sbbq	$0,%r10
-	movq	%r11,%r12
-	sbbq	L$poly+24(%rip),%r11
-	testq	%r13,%r13
-
-	cmovzq	%rax,%r8
-	cmovzq	%rdx,%r9
-	movq	%r8,0(%rdi)
-	cmovzq	%rcx,%r10
-	movq	%r9,8(%rdi)
-	cmovzq	%r12,%r11
-	movq	%r10,16(%rdi)
-	movq	%r11,24(%rdi)
-
-	popq	%r13
-	popq	%r12
-	.byte	0xf3,0xc3
-
-
-
-
-.globl	_ecp_nistz256_add
-.private_extern _ecp_nistz256_add
-
-.p2align	5
-_ecp_nistz256_add:
-	pushq	%r12
-	pushq	%r13
-
-	movq	0(%rsi),%r8
-	xorq	%r13,%r13
-	movq	8(%rsi),%r9
-	movq	16(%rsi),%r10
-	movq	24(%rsi),%r11
-	leaq	L$poly(%rip),%rsi
-
-	addq	0(%rdx),%r8
-	adcq	8(%rdx),%r9
-	movq	%r8,%rax
-	adcq	16(%rdx),%r10
-	adcq	24(%rdx),%r11
-	movq	%r9,%rdx
-	adcq	$0,%r13
-
-	subq	0(%rsi),%r8
-	movq	%r10,%rcx
-	sbbq	8(%rsi),%r9
-	sbbq	16(%rsi),%r10
-	movq	%r11,%r12
-	sbbq	24(%rsi),%r11
-	testq	%r13,%r13
-
-	cmovzq	%rax,%r8
-	cmovzq	%rdx,%r9
-	movq	%r8,0(%rdi)
-	cmovzq	%rcx,%r10
-	movq	%r9,8(%rdi)
-	cmovzq	%r12,%r11
-	movq	%r10,16(%rdi)
-	movq	%r11,24(%rdi)
-
-	popq	%r13
-	popq	%r12
-	.byte	0xf3,0xc3
-
-
-
-
-.globl	_ecp_nistz256_sub
-.private_extern _ecp_nistz256_sub
-
-.p2align	5
-_ecp_nistz256_sub:
-	pushq	%r12
-	pushq	%r13
-
-	movq	0(%rsi),%r8
-	xorq	%r13,%r13
-	movq	8(%rsi),%r9
-	movq	16(%rsi),%r10
-	movq	24(%rsi),%r11
-	leaq	L$poly(%rip),%rsi
-
-	subq	0(%rdx),%r8
-	sbbq	8(%rdx),%r9
-	movq	%r8,%rax
-	sbbq	16(%rdx),%r10
-	sbbq	24(%rdx),%r11
-	movq	%r9,%rdx
-	sbbq	$0,%r13
-
-	addq	0(%rsi),%r8
-	movq	%r10,%rcx
-	adcq	8(%rsi),%r9
-	adcq	16(%rsi),%r10
-	movq	%r11,%r12
-	adcq	24(%rsi),%r11
-	testq	%r13,%r13
-
-	cmovzq	%rax,%r8
-	cmovzq	%rdx,%r9
-	movq	%r8,0(%rdi)
-	cmovzq	%rcx,%r10
-	movq	%r9,8(%rdi)
-	cmovzq	%r12,%r11
-	movq	%r10,16(%rdi)
-	movq	%r11,24(%rdi)
-
-	popq	%r13
-	popq	%r12
-	.byte	0xf3,0xc3
-
-
-
-
 .globl	_ecp_nistz256_neg
 .private_extern _ecp_nistz256_neg
 
@@ -335,19 +107,6 @@
 
 
 
-.globl	_ecp_nistz256_to_mont
-.private_extern _ecp_nistz256_to_mont
-
-.p2align	5
-_ecp_nistz256_to_mont:
-	leaq	L$RR(%rip),%rdx
-	jmp	L$mul_mont
-
-
-
-
-
-
 
 
 .globl	_ecp_nistz256_mul_mont
diff --git a/third_party/boringssl/win-x86_64/crypto/bn/x86_64-mont5.asm b/third_party/boringssl/win-x86_64/crypto/bn/x86_64-mont5.asm
index 284318a..560b384 100644
--- a/third_party/boringssl/win-x86_64/crypto/bn/x86_64-mont5.asm
+++ b/third_party/boringssl/win-x86_64/crypto/bn/x86_64-mont5.asm
@@ -1616,6 +1616,15 @@
 ALIGN	32
 $L$8x_tail_done:
 	add	r8,QWORD[rdx]
+	adc	r9,0
+	adc	r10,0
+	adc	r11,0
+	adc	r12,0
+	adc	r13,0
+	adc	r14,0
+	adc	r15,0
+
+
 	xor	rax,rax
 
 	neg	rsi
diff --git a/third_party/boringssl/win-x86_64/crypto/ec/p256-x86_64-asm.asm b/third_party/boringssl/win-x86_64/crypto/ec/p256-x86_64-asm.asm
index c9789f5..45ba686c 100644
--- a/third_party/boringssl/win-x86_64/crypto/ec/p256-x86_64-asm.asm
+++ b/third_party/boringssl/win-x86_64/crypto/ec/p256-x86_64-asm.asm
@@ -11,10 +11,6 @@
 $L$poly:
 	DQ	0xffffffffffffffff,0x00000000ffffffff,0x0000000000000000,0xffffffff00000001
 
-
-$L$RR:
-	DQ	0x0000000000000003,0xfffffffbffffffff,0xfffffffffffffffe,0x00000004fffffffd
-
 $L$One:
 	DD	1,1,1,1,1,1,1,1
 $L$Two:
@@ -24,7 +20,6 @@
 $L$ONE_mont:
 	DQ	0x0000000000000001,0xffffffff00000000,0xffffffffffffffff,0x00000000fffffffe
 
-global	ecp_nistz256_mul_by_2
 
 ALIGN	64
 ecp_nistz256_mul_by_2:
@@ -78,266 +73,6 @@
 
 
 
-global	ecp_nistz256_div_by_2
-
-ALIGN	32
-ecp_nistz256_div_by_2:
-	mov	QWORD[8+rsp],rdi	;WIN64 prologue
-	mov	QWORD[16+rsp],rsi
-	mov	rax,rsp
-$L$SEH_begin_ecp_nistz256_div_by_2:
-	mov	rdi,rcx
-	mov	rsi,rdx
-
-
-	push	r12
-	push	r13
-
-	mov	r8,QWORD[rsi]
-	mov	r9,QWORD[8+rsi]
-	mov	r10,QWORD[16+rsi]
-	mov	rax,r8
-	mov	r11,QWORD[24+rsi]
-	lea	rsi,[$L$poly]
-
-	mov	rdx,r9
-	xor	r13,r13
-	add	r8,QWORD[rsi]
-	mov	rcx,r10
-	adc	r9,QWORD[8+rsi]
-	adc	r10,QWORD[16+rsi]
-	mov	r12,r11
-	adc	r11,QWORD[24+rsi]
-	adc	r13,0
-	xor	rsi,rsi
-	test	rax,1
-
-	cmovz	r8,rax
-	cmovz	r9,rdx
-	cmovz	r10,rcx
-	cmovz	r11,r12
-	cmovz	r13,rsi
-
-	mov	rax,r9
-	shr	r8,1
-	shl	rax,63
-	mov	rdx,r10
-	shr	r9,1
-	or	r8,rax
-	shl	rdx,63
-	mov	rcx,r11
-	shr	r10,1
-	or	r9,rdx
-	shl	rcx,63
-	shr	r11,1
-	shl	r13,63
-	or	r10,rcx
-	or	r11,r13
-
-	mov	QWORD[rdi],r8
-	mov	QWORD[8+rdi],r9
-	mov	QWORD[16+rdi],r10
-	mov	QWORD[24+rdi],r11
-
-	pop	r13
-	pop	r12
-	mov	rdi,QWORD[8+rsp]	;WIN64 epilogue
-	mov	rsi,QWORD[16+rsp]
-	DB	0F3h,0C3h		;repret
-$L$SEH_end_ecp_nistz256_div_by_2:
-
-
-
-global	ecp_nistz256_mul_by_3
-
-ALIGN	32
-ecp_nistz256_mul_by_3:
-	mov	QWORD[8+rsp],rdi	;WIN64 prologue
-	mov	QWORD[16+rsp],rsi
-	mov	rax,rsp
-$L$SEH_begin_ecp_nistz256_mul_by_3:
-	mov	rdi,rcx
-	mov	rsi,rdx
-
-
-	push	r12
-	push	r13
-
-	mov	r8,QWORD[rsi]
-	xor	r13,r13
-	mov	r9,QWORD[8+rsi]
-	add	r8,r8
-	mov	r10,QWORD[16+rsi]
-	adc	r9,r9
-	mov	r11,QWORD[24+rsi]
-	mov	rax,r8
-	adc	r10,r10
-	adc	r11,r11
-	mov	rdx,r9
-	adc	r13,0
-
-	sub	r8,-1
-	mov	rcx,r10
-	sbb	r9,QWORD[(($L$poly+8))]
-	sbb	r10,0
-	mov	r12,r11
-	sbb	r11,QWORD[(($L$poly+24))]
-	test	r13,r13
-
-	cmovz	r8,rax
-	cmovz	r9,rdx
-	cmovz	r10,rcx
-	cmovz	r11,r12
-
-	xor	r13,r13
-	add	r8,QWORD[rsi]
-	adc	r9,QWORD[8+rsi]
-	mov	rax,r8
-	adc	r10,QWORD[16+rsi]
-	adc	r11,QWORD[24+rsi]
-	mov	rdx,r9
-	adc	r13,0
-
-	sub	r8,-1
-	mov	rcx,r10
-	sbb	r9,QWORD[(($L$poly+8))]
-	sbb	r10,0
-	mov	r12,r11
-	sbb	r11,QWORD[(($L$poly+24))]
-	test	r13,r13
-
-	cmovz	r8,rax
-	cmovz	r9,rdx
-	mov	QWORD[rdi],r8
-	cmovz	r10,rcx
-	mov	QWORD[8+rdi],r9
-	cmovz	r11,r12
-	mov	QWORD[16+rdi],r10
-	mov	QWORD[24+rdi],r11
-
-	pop	r13
-	pop	r12
-	mov	rdi,QWORD[8+rsp]	;WIN64 epilogue
-	mov	rsi,QWORD[16+rsp]
-	DB	0F3h,0C3h		;repret
-$L$SEH_end_ecp_nistz256_mul_by_3:
-
-
-
-global	ecp_nistz256_add
-
-ALIGN	32
-ecp_nistz256_add:
-	mov	QWORD[8+rsp],rdi	;WIN64 prologue
-	mov	QWORD[16+rsp],rsi
-	mov	rax,rsp
-$L$SEH_begin_ecp_nistz256_add:
-	mov	rdi,rcx
-	mov	rsi,rdx
-	mov	rdx,r8
-
-
-	push	r12
-	push	r13
-
-	mov	r8,QWORD[rsi]
-	xor	r13,r13
-	mov	r9,QWORD[8+rsi]
-	mov	r10,QWORD[16+rsi]
-	mov	r11,QWORD[24+rsi]
-	lea	rsi,[$L$poly]
-
-	add	r8,QWORD[rdx]
-	adc	r9,QWORD[8+rdx]
-	mov	rax,r8
-	adc	r10,QWORD[16+rdx]
-	adc	r11,QWORD[24+rdx]
-	mov	rdx,r9
-	adc	r13,0
-
-	sub	r8,QWORD[rsi]
-	mov	rcx,r10
-	sbb	r9,QWORD[8+rsi]
-	sbb	r10,QWORD[16+rsi]
-	mov	r12,r11
-	sbb	r11,QWORD[24+rsi]
-	test	r13,r13
-
-	cmovz	r8,rax
-	cmovz	r9,rdx
-	mov	QWORD[rdi],r8
-	cmovz	r10,rcx
-	mov	QWORD[8+rdi],r9
-	cmovz	r11,r12
-	mov	QWORD[16+rdi],r10
-	mov	QWORD[24+rdi],r11
-
-	pop	r13
-	pop	r12
-	mov	rdi,QWORD[8+rsp]	;WIN64 epilogue
-	mov	rsi,QWORD[16+rsp]
-	DB	0F3h,0C3h		;repret
-$L$SEH_end_ecp_nistz256_add:
-
-
-
-global	ecp_nistz256_sub
-
-ALIGN	32
-ecp_nistz256_sub:
-	mov	QWORD[8+rsp],rdi	;WIN64 prologue
-	mov	QWORD[16+rsp],rsi
-	mov	rax,rsp
-$L$SEH_begin_ecp_nistz256_sub:
-	mov	rdi,rcx
-	mov	rsi,rdx
-	mov	rdx,r8
-
-
-	push	r12
-	push	r13
-
-	mov	r8,QWORD[rsi]
-	xor	r13,r13
-	mov	r9,QWORD[8+rsi]
-	mov	r10,QWORD[16+rsi]
-	mov	r11,QWORD[24+rsi]
-	lea	rsi,[$L$poly]
-
-	sub	r8,QWORD[rdx]
-	sbb	r9,QWORD[8+rdx]
-	mov	rax,r8
-	sbb	r10,QWORD[16+rdx]
-	sbb	r11,QWORD[24+rdx]
-	mov	rdx,r9
-	sbb	r13,0
-
-	add	r8,QWORD[rsi]
-	mov	rcx,r10
-	adc	r9,QWORD[8+rsi]
-	adc	r10,QWORD[16+rsi]
-	mov	r12,r11
-	adc	r11,QWORD[24+rsi]
-	test	r13,r13
-
-	cmovz	r8,rax
-	cmovz	r9,rdx
-	mov	QWORD[rdi],r8
-	cmovz	r10,rcx
-	mov	QWORD[8+rdi],r9
-	cmovz	r11,r12
-	mov	QWORD[16+rdi],r10
-	mov	QWORD[24+rdi],r11
-
-	pop	r13
-	pop	r12
-	mov	rdi,QWORD[8+rsp]	;WIN64 epilogue
-	mov	rsi,QWORD[16+rsp]
-	DB	0F3h,0C3h		;repret
-$L$SEH_end_ecp_nistz256_sub:
-
-
-
 global	ecp_nistz256_neg
 
 ALIGN	32
@@ -395,26 +130,6 @@
 
 
 
-global	ecp_nistz256_to_mont
-
-ALIGN	32
-ecp_nistz256_to_mont:
-	mov	QWORD[8+rsp],rdi	;WIN64 prologue
-	mov	QWORD[16+rsp],rsi
-	mov	rax,rsp
-$L$SEH_begin_ecp_nistz256_to_mont:
-	mov	rdi,rcx
-	mov	rsi,rdx
-
-
-	lea	rdx,[$L$RR]
-	jmp	NEAR $L$mul_mont
-$L$SEH_end_ecp_nistz256_to_mont:
-
-
-
-
-
 
 
 global	ecp_nistz256_mul_mont
diff --git a/third_party/mojo/src/mojo/edk/embedder/embedder.cc b/third_party/mojo/src/mojo/edk/embedder/embedder.cc
index 9daa0517..692547ac 100644
--- a/third_party/mojo/src/mojo/edk/embedder/embedder.cc
+++ b/third_party/mojo/src/mojo/edk/embedder/embedder.cc
@@ -4,6 +4,8 @@
 
 #include "third_party/mojo/src/mojo/edk/embedder/embedder.h"
 
+#include <utility>
+
 #include "base/atomicops.h"
 #include "base/bind.h"
 #include "base/bind_helpers.h"
@@ -283,7 +285,7 @@
   scoped_refptr<system::MessagePipeDispatcher> dispatcher =
       internal::g_ipc_support->ConnectToSlave(
           connection_id, slave_info, platform_handle.Pass(),
-          did_connect_to_slave_callback, did_connect_to_slave_runner.Pass(),
+          did_connect_to_slave_callback, std::move(did_connect_to_slave_runner),
           &channel_id);
   *channel_info = new ChannelInfo(channel_id);
 
@@ -312,7 +314,7 @@
   scoped_refptr<system::MessagePipeDispatcher> dispatcher =
       internal::g_ipc_support->ConnectToMaster(
           connection_id, did_connect_to_master_callback,
-          did_connect_to_master_runner.Pass(), &channel_id);
+          std::move(did_connect_to_master_runner), &channel_id);
   *channel_info = new ChannelInfo(channel_id);
 
   ScopedMessagePipeHandle rv(
diff --git a/third_party/mojo/src/mojo/edk/system/channel.cc b/third_party/mojo/src/mojo/edk/system/channel.cc
index b0101b5c..0b3e9f85 100644
--- a/third_party/mojo/src/mojo/edk/system/channel.cc
+++ b/third_party/mojo/src/mojo/edk/system/channel.cc
@@ -5,6 +5,7 @@
 #include "third_party/mojo/src/mojo/edk/system/channel.h"
 
 #include <algorithm>
+#include <utility>
 
 #include "base/bind.h"
 #include "base/logging.h"
@@ -126,7 +127,7 @@
 void Channel::SetBootstrapEndpoint(scoped_refptr<ChannelEndpoint> endpoint) {
   // Used for both local and remote IDs.
   ChannelEndpointId bootstrap_id = ChannelEndpointId::GetBootstrap();
-  SetBootstrapEndpointWithIds(endpoint.Pass(), bootstrap_id, bootstrap_id);
+  SetBootstrapEndpointWithIds(std::move(endpoint), bootstrap_id, bootstrap_id);
 }
 
 void Channel::SetBootstrapEndpointWithIds(
diff --git a/third_party/mojo/src/mojo/edk/system/ipc_support.cc b/third_party/mojo/src/mojo/edk/system/ipc_support.cc
index ba4f05f..1738578 100644
--- a/third_party/mojo/src/mojo/edk/system/ipc_support.cc
+++ b/third_party/mojo/src/mojo/edk/system/ipc_support.cc
@@ -4,6 +4,8 @@
 
 #include "third_party/mojo/src/mojo/edk/system/ipc_support.h"
 
+#include <utility>
+
 #include "base/logging.h"
 #include "third_party/mojo/src/mojo/edk/embedder/master_process_delegate.h"
 #include "third_party/mojo/src/mojo/edk/embedder/slave_process_delegate.h"
@@ -15,15 +17,14 @@
 namespace mojo {
 namespace system {
 
-IPCSupport::IPCSupport(
-    embedder::PlatformSupport* platform_support,
-    embedder::ProcessType process_type,
-    embedder::ProcessDelegate* process_delegate,
-    scoped_refptr<base::TaskRunner> io_thread_task_runner,
-    embedder::ScopedPlatformHandle platform_handle)
+IPCSupport::IPCSupport(embedder::PlatformSupport* platform_support,
+                       embedder::ProcessType process_type,
+                       embedder::ProcessDelegate* process_delegate,
+                       scoped_refptr<base::TaskRunner> io_thread_task_runner,
+                       embedder::ScopedPlatformHandle platform_handle)
     : process_type_(process_type),
       process_delegate_(process_delegate),
-      io_thread_task_runner_(io_thread_task_runner.Pass()) {
+      io_thread_task_runner_(std::move(io_thread_task_runner)) {
   DCHECK(io_thread_task_runner_);
 
   switch (process_type_) {
diff --git a/third_party/mojo/src/mojo/edk/system/ipc_support_unittest.cc b/third_party/mojo/src/mojo/edk/system/ipc_support_unittest.cc
index 2df558e..4ebaafd 100644
--- a/third_party/mojo/src/mojo/edk/system/ipc_support_unittest.cc
+++ b/third_party/mojo/src/mojo/edk/system/ipc_support_unittest.cc
@@ -319,11 +319,11 @@
   }
 
   scoped_refptr<MessagePipeDispatcher> PassMasterMessagePipe() {
-    return master_mp_.Pass();
+    return std::move(master_mp_);
   }
 
   scoped_refptr<MessagePipeDispatcher> PassSlaveMessagePipe() {
-    return slave_mp_.Pass();
+    return std::move(slave_mp_);
   }
 
   void Shutdown() {
@@ -652,7 +652,8 @@
   embedder::ScopedPlatformHandle second_platform_handle =
       master_ipc_support().ConnectToSlaveInternal(
           connection_id, nullptr,
-          multiprocess_test_helper.server_platform_handle.Pass(), &slave_id);
+          std::move(multiprocess_test_helper.server_platform_handle),
+          &slave_id);
   ASSERT_TRUE(second_platform_handle.is_valid());
   EXPECT_NE(slave_id, kInvalidProcessIdentifier);
   EXPECT_NE(slave_id, kMasterProcessIdentifier);
@@ -682,7 +683,7 @@
 
 MOJO_MULTIPROCESS_TEST_CHILD_TEST(MultiprocessMasterSlaveInternal) {
   embedder::ScopedPlatformHandle client_platform_handle =
-      mojo::test::MultiprocessTestHelper::client_platform_handle.Pass();
+      std::move(mojo::test::MultiprocessTestHelper::client_platform_handle);
   ASSERT_TRUE(client_platform_handle.is_valid());
 
   embedder::SimplePlatformSupport platform_support;
@@ -692,7 +693,7 @@
   // Note: Run process delegate methods on the I/O thread.
   IPCSupport ipc_support(&platform_support, embedder::ProcessType::SLAVE,
                          &slave_process_delegate, test_io_thread.task_runner(),
-                         client_platform_handle.Pass());
+                         std::move(client_platform_handle));
 
   const base::CommandLine& command_line =
       *base::CommandLine::ForCurrentProcess();
diff --git a/third_party/mojo/src/mojo/edk/system/shared_buffer_dispatcher.cc b/third_party/mojo/src/mojo/edk/system/shared_buffer_dispatcher.cc
index 75c85cfa..8c64e1a 100644
--- a/third_party/mojo/src/mojo/edk/system/shared_buffer_dispatcher.cc
+++ b/third_party/mojo/src/mojo/edk/system/shared_buffer_dispatcher.cc
@@ -5,6 +5,7 @@
 #include "third_party/mojo/src/mojo/edk/system/shared_buffer_dispatcher.h"
 
 #include <limits>
+#include <utility>
 
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
@@ -77,7 +78,7 @@
   if (!shared_buffer)
     return MOJO_RESULT_RESOURCE_EXHAUSTED;
 
-  *result = CreateInternal(shared_buffer.Pass());
+  *result = CreateInternal(std::move(shared_buffer));
   return MOJO_RESULT_OK;
 }
 
@@ -132,7 +133,7 @@
     return nullptr;
   }
 
-  return CreateInternal(shared_buffer.Pass());
+  return CreateInternal(std::move(shared_buffer));
 }
 
 SharedBufferDispatcher::SharedBufferDispatcher(
@@ -186,7 +187,7 @@
 SharedBufferDispatcher::CreateEquivalentDispatcherAndCloseImplNoLock() {
   mutex().AssertHeld();
   DCHECK(shared_buffer_);
-  return CreateInternal(shared_buffer_.Pass());
+  return CreateInternal(std::move(shared_buffer_));
 }
 
 MojoResult SharedBufferDispatcher::DuplicateBufferHandleImplNoLock(
diff --git a/third_party/mojo/src/mojo/edk/system/shared_buffer_dispatcher.h b/third_party/mojo/src/mojo/edk/system/shared_buffer_dispatcher.h
index 3e6d4f25..49fda03 100644
--- a/third_party/mojo/src/mojo/edk/system/shared_buffer_dispatcher.h
+++ b/third_party/mojo/src/mojo/edk/system/shared_buffer_dispatcher.h
@@ -5,6 +5,8 @@
 #ifndef THIRD_PARTY_MOJO_SRC_MOJO_EDK_SYSTEM_SHARED_BUFFER_DISPATCHER_H_
 #define THIRD_PARTY_MOJO_SRC_MOJO_EDK_SYSTEM_SHARED_BUFFER_DISPATCHER_H_
 
+#include <utility>
+
 #include "mojo/public/cpp/system/macros.h"
 #include "third_party/mojo/src/mojo/edk/embedder/platform_shared_buffer.h"
 #include "third_party/mojo/src/mojo/edk/system/memory.h"
@@ -63,7 +65,8 @@
  private:
   static scoped_refptr<SharedBufferDispatcher> CreateInternal(
       scoped_refptr<embedder::PlatformSharedBuffer> shared_buffer) {
-    return make_scoped_refptr(new SharedBufferDispatcher(shared_buffer.Pass()));
+    return make_scoped_refptr(
+        new SharedBufferDispatcher(std::move(shared_buffer)));
   }
 
   explicit SharedBufferDispatcher(
diff --git a/third_party/mojo/src/mojo/edk/test/scoped_ipc_support.cc b/third_party/mojo/src/mojo/edk/test/scoped_ipc_support.cc
index 4965b940..e5e338c1 100644
--- a/third_party/mojo/src/mojo/edk/test/scoped_ipc_support.cc
+++ b/third_party/mojo/src/mojo/edk/test/scoped_ipc_support.cc
@@ -4,6 +4,8 @@
 
 #include "third_party/mojo/src/mojo/edk/test/scoped_ipc_support.h"
 
+#include <utility>
+
 #include "base/message_loop/message_loop.h"
 #include "third_party/mojo/src/mojo/edk/embedder/embedder.h"
 
@@ -33,7 +35,7 @@
   io_thread_task_runner_ = io_thread_task_runner;
   // Note: Run delegate methods on the I/O thread.
   embedder::InitIPCSupport(process_type, process_delegate,
-                           io_thread_task_runner_, platform_handle.Pass());
+                           io_thread_task_runner_, std::move(platform_handle));
 }
 
 void ScopedIPCSupportHelper::OnShutdownCompleteImpl() {
@@ -44,7 +46,8 @@
 
 ScopedIPCSupport::ScopedIPCSupport(
     scoped_refptr<base::TaskRunner> io_thread_task_runner) {
-  helper_.Init(embedder::ProcessType::NONE, this, io_thread_task_runner.Pass(),
+  helper_.Init(embedder::ProcessType::NONE, this,
+               std::move(io_thread_task_runner),
                embedder::ScopedPlatformHandle());
 }
 
@@ -58,7 +61,8 @@
 ScopedMasterIPCSupport::ScopedMasterIPCSupport(
     scoped_refptr<base::TaskRunner> io_thread_task_runner) {
   helper_.Init(embedder::ProcessType::MASTER, this,
-               io_thread_task_runner.Pass(), embedder::ScopedPlatformHandle());
+               std::move(io_thread_task_runner),
+               embedder::ScopedPlatformHandle());
 }
 
 ScopedMasterIPCSupport::ScopedMasterIPCSupport(
@@ -66,7 +70,8 @@
     base::Callback<void(embedder::SlaveInfo slave_info)> on_slave_disconnect)
     : on_slave_disconnect_(on_slave_disconnect) {
   helper_.Init(embedder::ProcessType::MASTER, this,
-               io_thread_task_runner.Pass(), embedder::ScopedPlatformHandle());
+               std::move(io_thread_task_runner),
+               embedder::ScopedPlatformHandle());
 }
 
 ScopedMasterIPCSupport::~ScopedMasterIPCSupport() {
@@ -84,8 +89,8 @@
 ScopedSlaveIPCSupport::ScopedSlaveIPCSupport(
     scoped_refptr<base::TaskRunner> io_thread_task_runner,
     embedder::ScopedPlatformHandle platform_handle) {
-  helper_.Init(embedder::ProcessType::SLAVE, this, io_thread_task_runner.Pass(),
-               platform_handle.Pass());
+  helper_.Init(embedder::ProcessType::SLAVE, this,
+               std::move(io_thread_task_runner), std::move(platform_handle));
 }
 
 ScopedSlaveIPCSupport::ScopedSlaveIPCSupport(
@@ -93,8 +98,8 @@
     embedder::ScopedPlatformHandle platform_handle,
     base::Closure on_master_disconnect)
     : on_master_disconnect_(on_master_disconnect) {
-  helper_.Init(embedder::ProcessType::SLAVE, this, io_thread_task_runner.Pass(),
-               platform_handle.Pass());
+  helper_.Init(embedder::ProcessType::SLAVE, this,
+               std::move(io_thread_task_runner), std::move(platform_handle));
 }
 
 ScopedSlaveIPCSupport::~ScopedSlaveIPCSupport() {
diff --git a/third_party/mojo/src/mojo/public/c/gles2/gles2_call_visitor_chromium_extension_autogen.h b/third_party/mojo/src/mojo/public/c/gles2/gles2_call_visitor_chromium_extension_autogen.h
new file mode 100644
index 0000000..88ab603a
--- /dev/null
+++ b/third_party/mojo/src/mojo/public/c/gles2/gles2_call_visitor_chromium_extension_autogen.h
@@ -0,0 +1,568 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is auto-generated from
+// gpu/command_buffer/build_gles2_cmd_buffer.py
+// It's formatted by clang-format using chromium coding style:
+//    clang-format -i -style=chromium filename
+// DO NOT EDIT!
+
+VISIT_GL_CALL(ShallowFinishCHROMIUM, void, (), ())
+VISIT_GL_CALL(ShallowFlushCHROMIUM, void, (), ())
+VISIT_GL_CALL(OrderingBarrierCHROMIUM, void, (), ())
+VISIT_GL_CALL(
+    BlitFramebufferCHROMIUM,
+    void,
+    (GLint srcX0,
+     GLint srcY0,
+     GLint srcX1,
+     GLint srcY1,
+     GLint dstX0,
+     GLint dstY0,
+     GLint dstX1,
+     GLint dstY1,
+     GLbitfield mask,
+     GLenum filter),
+    (srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter))
+VISIT_GL_CALL(RenderbufferStorageMultisampleCHROMIUM,
+              void,
+              (GLenum target,
+               GLsizei samples,
+               GLenum internalformat,
+               GLsizei width,
+               GLsizei height),
+              (target, samples, internalformat, width, height))
+VISIT_GL_CALL(RenderbufferStorageMultisampleEXT,
+              void,
+              (GLenum target,
+               GLsizei samples,
+               GLenum internalformat,
+               GLsizei width,
+               GLsizei height),
+              (target, samples, internalformat, width, height))
+VISIT_GL_CALL(FramebufferTexture2DMultisampleEXT,
+              void,
+              (GLenum target,
+               GLenum attachment,
+               GLenum textarget,
+               GLuint texture,
+               GLint level,
+               GLsizei samples),
+              (target, attachment, textarget, texture, level, samples))
+VISIT_GL_CALL(TexStorage2DEXT,
+              void,
+              (GLenum target,
+               GLsizei levels,
+               GLenum internalFormat,
+               GLsizei width,
+               GLsizei height),
+              (target, levels, internalFormat, width, height))
+VISIT_GL_CALL(GenQueriesEXT, void, (GLsizei n, GLuint* queries), (n, queries))
+VISIT_GL_CALL(DeleteQueriesEXT,
+              void,
+              (GLsizei n, const GLuint* queries),
+              (n, queries))
+VISIT_GL_CALL(QueryCounterEXT, void, (GLuint id, GLenum target), (id, target))
+VISIT_GL_CALL(IsQueryEXT, GLboolean, (GLuint id), (id))
+VISIT_GL_CALL(BeginQueryEXT, void, (GLenum target, GLuint id), (target, id))
+VISIT_GL_CALL(EndQueryEXT, void, (GLenum target), (target))
+VISIT_GL_CALL(GetQueryivEXT,
+              void,
+              (GLenum target, GLenum pname, GLint* params),
+              (target, pname, params))
+VISIT_GL_CALL(GetQueryObjectivEXT,
+              void,
+              (GLuint id, GLenum pname, GLint* params),
+              (id, pname, params))
+VISIT_GL_CALL(GetQueryObjectuivEXT,
+              void,
+              (GLuint id, GLenum pname, GLuint* params),
+              (id, pname, params))
+VISIT_GL_CALL(GetQueryObjecti64vEXT,
+              void,
+              (GLuint id, GLenum pname, GLint64* params),
+              (id, pname, params))
+VISIT_GL_CALL(GetQueryObjectui64vEXT,
+              void,
+              (GLuint id, GLenum pname, GLuint64* params),
+              (id, pname, params))
+VISIT_GL_CALL(SetDisjointValueSyncCHROMIUM, void, (), ())
+VISIT_GL_CALL(InsertEventMarkerEXT,
+              void,
+              (GLsizei length, const GLchar* marker),
+              (length, marker))
+VISIT_GL_CALL(PushGroupMarkerEXT,
+              void,
+              (GLsizei length, const GLchar* marker),
+              (length, marker))
+VISIT_GL_CALL(PopGroupMarkerEXT, void, (), ())
+VISIT_GL_CALL(GenVertexArraysOES,
+              void,
+              (GLsizei n, GLuint* arrays),
+              (n, arrays))
+VISIT_GL_CALL(DeleteVertexArraysOES,
+              void,
+              (GLsizei n, const GLuint* arrays),
+              (n, arrays))
+VISIT_GL_CALL(IsVertexArrayOES, GLboolean, (GLuint array), (array))
+VISIT_GL_CALL(BindVertexArrayOES, void, (GLuint array), (array))
+VISIT_GL_CALL(SwapBuffers, void, (), ())
+VISIT_GL_CALL(GetMaxValueInBufferCHROMIUM,
+              GLuint,
+              (GLuint buffer_id, GLsizei count, GLenum type, GLuint offset),
+              (buffer_id, count, type, offset))
+VISIT_GL_CALL(EnableFeatureCHROMIUM,
+              GLboolean,
+              (const char* feature),
+              (feature))
+VISIT_GL_CALL(MapBufferCHROMIUM,
+              void*,
+              (GLuint target, GLenum access),
+              (target, access))
+VISIT_GL_CALL(UnmapBufferCHROMIUM, GLboolean, (GLuint target), (target))
+VISIT_GL_CALL(MapBufferSubDataCHROMIUM,
+              void*,
+              (GLuint target, GLintptr offset, GLsizeiptr size, GLenum access),
+              (target, offset, size, access))
+VISIT_GL_CALL(UnmapBufferSubDataCHROMIUM, void, (const void* mem), (mem))
+VISIT_GL_CALL(
+    MapTexSubImage2DCHROMIUM,
+    void*,
+    (GLenum target,
+     GLint level,
+     GLint xoffset,
+     GLint yoffset,
+     GLsizei width,
+     GLsizei height,
+     GLenum format,
+     GLenum type,
+     GLenum access),
+    (target, level, xoffset, yoffset, width, height, format, type, access))
+VISIT_GL_CALL(UnmapTexSubImage2DCHROMIUM, void, (const void* mem), (mem))
+VISIT_GL_CALL(ResizeCHROMIUM,
+              void,
+              (GLuint width, GLuint height, GLfloat scale_factor),
+              (width, height, scale_factor))
+VISIT_GL_CALL(GetRequestableExtensionsCHROMIUM, const GLchar*, (), ())
+VISIT_GL_CALL(RequestExtensionCHROMIUM,
+              void,
+              (const char* extension),
+              (extension))
+VISIT_GL_CALL(GetProgramInfoCHROMIUM,
+              void,
+              (GLuint program, GLsizei bufsize, GLsizei* size, void* info),
+              (program, bufsize, size, info))
+VISIT_GL_CALL(CreateStreamTextureCHROMIUM, GLuint, (GLuint texture), (texture))
+VISIT_GL_CALL(
+    CreateImageCHROMIUM,
+    GLuint,
+    (ClientBuffer buffer, GLsizei width, GLsizei height, GLenum internalformat),
+    (buffer, width, height, internalformat))
+VISIT_GL_CALL(DestroyImageCHROMIUM, void, (GLuint image_id), (image_id))
+VISIT_GL_CALL(
+    CreateGpuMemoryBufferImageCHROMIUM,
+    GLuint,
+    (GLsizei width, GLsizei height, GLenum internalformat, GLenum usage),
+    (width, height, internalformat, usage))
+VISIT_GL_CALL(GetTranslatedShaderSourceANGLE,
+              void,
+              (GLuint shader, GLsizei bufsize, GLsizei* length, char* source),
+              (shader, bufsize, length, source))
+VISIT_GL_CALL(PostSubBufferCHROMIUM,
+              void,
+              (GLint x, GLint y, GLint width, GLint height),
+              (x, y, width, height))
+VISIT_GL_CALL(TexImageIOSurface2DCHROMIUM,
+              void,
+              (GLenum target,
+               GLsizei width,
+               GLsizei height,
+               GLuint ioSurfaceId,
+               GLuint plane),
+              (target, width, height, ioSurfaceId, plane))
+VISIT_GL_CALL(CopyTextureCHROMIUM,
+              void,
+              (GLenum target,
+               GLenum source_id,
+               GLenum dest_id,
+               GLint internalformat,
+               GLenum dest_type,
+               GLboolean unpack_flip_y,
+               GLboolean unpack_premultiply_alpha,
+               GLboolean unpack_unmultiply_alpha),
+              (target,
+               source_id,
+               dest_id,
+               internalformat,
+               dest_type,
+               unpack_flip_y,
+               unpack_premultiply_alpha,
+               unpack_unmultiply_alpha))
+VISIT_GL_CALL(CopySubTextureCHROMIUM,
+              void,
+              (GLenum target,
+               GLenum source_id,
+               GLenum dest_id,
+               GLint xoffset,
+               GLint yoffset,
+               GLint x,
+               GLint y,
+               GLsizei width,
+               GLsizei height,
+               GLboolean unpack_flip_y,
+               GLboolean unpack_premultiply_alpha,
+               GLboolean unpack_unmultiply_alpha),
+              (target,
+               source_id,
+               dest_id,
+               xoffset,
+               yoffset,
+               x,
+               y,
+               width,
+               height,
+               unpack_flip_y,
+               unpack_premultiply_alpha,
+               unpack_unmultiply_alpha))
+VISIT_GL_CALL(CompressedCopyTextureCHROMIUM,
+              void,
+              (GLenum target, GLenum source_id, GLenum dest_id),
+              (target, source_id, dest_id))
+VISIT_GL_CALL(
+    CompressedCopySubTextureCHROMIUM,
+    void,
+    (GLenum target,
+     GLenum source_id,
+     GLenum dest_id,
+     GLint xoffset,
+     GLint yoffset,
+     GLint x,
+     GLint y,
+     GLsizei width,
+     GLsizei height),
+    (target, source_id, dest_id, xoffset, yoffset, x, y, width, height))
+VISIT_GL_CALL(DrawArraysInstancedANGLE,
+              void,
+              (GLenum mode, GLint first, GLsizei count, GLsizei primcount),
+              (mode, first, count, primcount))
+VISIT_GL_CALL(DrawElementsInstancedANGLE,
+              void,
+              (GLenum mode,
+               GLsizei count,
+               GLenum type,
+               const void* indices,
+               GLsizei primcount),
+              (mode, count, type, indices, primcount))
+VISIT_GL_CALL(VertexAttribDivisorANGLE,
+              void,
+              (GLuint index, GLuint divisor),
+              (index, divisor))
+VISIT_GL_CALL(GenMailboxCHROMIUM, void, (GLbyte * mailbox), (mailbox))
+VISIT_GL_CALL(ProduceTextureCHROMIUM,
+              void,
+              (GLenum target, const GLbyte* mailbox),
+              (target, mailbox))
+VISIT_GL_CALL(ProduceTextureDirectCHROMIUM,
+              void,
+              (GLuint texture, GLenum target, const GLbyte* mailbox),
+              (texture, target, mailbox))
+VISIT_GL_CALL(ConsumeTextureCHROMIUM,
+              void,
+              (GLenum target, const GLbyte* mailbox),
+              (target, mailbox))
+VISIT_GL_CALL(CreateAndConsumeTextureCHROMIUM,
+              GLuint,
+              (GLenum target, const GLbyte* mailbox),
+              (target, mailbox))
+VISIT_GL_CALL(BindUniformLocationCHROMIUM,
+              void,
+              (GLuint program, GLint location, const char* name),
+              (program, location, name))
+VISIT_GL_CALL(GenValuebuffersCHROMIUM,
+              void,
+              (GLsizei n, GLuint* buffers),
+              (n, buffers))
+VISIT_GL_CALL(DeleteValuebuffersCHROMIUM,
+              void,
+              (GLsizei n, const GLuint* valuebuffers),
+              (n, valuebuffers))
+VISIT_GL_CALL(IsValuebufferCHROMIUM,
+              GLboolean,
+              (GLuint valuebuffer),
+              (valuebuffer))
+VISIT_GL_CALL(BindValuebufferCHROMIUM,
+              void,
+              (GLenum target, GLuint valuebuffer),
+              (target, valuebuffer))
+VISIT_GL_CALL(SubscribeValueCHROMIUM,
+              void,
+              (GLenum target, GLenum subscription),
+              (target, subscription))
+VISIT_GL_CALL(PopulateSubscribedValuesCHROMIUM, void, (GLenum target), (target))
+VISIT_GL_CALL(UniformValuebufferCHROMIUM,
+              void,
+              (GLint location, GLenum target, GLenum subscription),
+              (location, target, subscription))
+VISIT_GL_CALL(BindTexImage2DCHROMIUM,
+              void,
+              (GLenum target, GLint imageId),
+              (target, imageId))
+VISIT_GL_CALL(ReleaseTexImage2DCHROMIUM,
+              void,
+              (GLenum target, GLint imageId),
+              (target, imageId))
+VISIT_GL_CALL(TraceBeginCHROMIUM,
+              void,
+              (const char* category_name, const char* trace_name),
+              (category_name, trace_name))
+VISIT_GL_CALL(TraceEndCHROMIUM, void, (), ())
+VISIT_GL_CALL(DiscardFramebufferEXT,
+              void,
+              (GLenum target, GLsizei count, const GLenum* attachments),
+              (target, count, attachments))
+VISIT_GL_CALL(LoseContextCHROMIUM,
+              void,
+              (GLenum current, GLenum other),
+              (current, other))
+VISIT_GL_CALL(InsertSyncPointCHROMIUM, GLuint, (), ())
+VISIT_GL_CALL(WaitSyncPointCHROMIUM, void, (GLuint sync_point), (sync_point))
+VISIT_GL_CALL(InsertFenceSyncCHROMIUM, GLuint64, (), ())
+VISIT_GL_CALL(GenSyncTokenCHROMIUM,
+              void,
+              (GLuint64 fence_sync, GLbyte* sync_token),
+              (fence_sync, sync_token))
+VISIT_GL_CALL(GenUnverifiedSyncTokenCHROMIUM,
+              void,
+              (GLuint64 fence_sync, GLbyte* sync_token),
+              (fence_sync, sync_token))
+VISIT_GL_CALL(WaitSyncTokenCHROMIUM,
+              void,
+              (const GLbyte* sync_token),
+              (sync_token))
+VISIT_GL_CALL(DrawBuffersEXT,
+              void,
+              (GLsizei count, const GLenum* bufs),
+              (count, bufs))
+VISIT_GL_CALL(DiscardBackbufferCHROMIUM, void, (), ())
+VISIT_GL_CALL(ScheduleOverlayPlaneCHROMIUM,
+              void,
+              (GLint plane_z_order,
+               GLenum plane_transform,
+               GLuint overlay_texture_id,
+               GLint bounds_x,
+               GLint bounds_y,
+               GLint bounds_width,
+               GLint bounds_height,
+               GLfloat uv_x,
+               GLfloat uv_y,
+               GLfloat uv_width,
+               GLfloat uv_height),
+              (plane_z_order,
+               plane_transform,
+               overlay_texture_id,
+               bounds_x,
+               bounds_y,
+               bounds_width,
+               bounds_height,
+               uv_x,
+               uv_y,
+               uv_width,
+               uv_height))
+VISIT_GL_CALL(SwapInterval, void, (GLint interval), (interval))
+VISIT_GL_CALL(FlushDriverCachesCHROMIUM, void, (), ())
+VISIT_GL_CALL(MatrixLoadfCHROMIUM,
+              void,
+              (GLenum matrixMode, const GLfloat* m),
+              (matrixMode, m))
+VISIT_GL_CALL(MatrixLoadIdentityCHROMIUM,
+              void,
+              (GLenum matrixMode),
+              (matrixMode))
+VISIT_GL_CALL(GenPathsCHROMIUM, GLuint, (GLsizei range), (range))
+VISIT_GL_CALL(DeletePathsCHROMIUM,
+              void,
+              (GLuint path, GLsizei range),
+              (path, range))
+VISIT_GL_CALL(IsPathCHROMIUM, GLboolean, (GLuint path), (path))
+VISIT_GL_CALL(PathCommandsCHROMIUM,
+              void,
+              (GLuint path,
+               GLsizei numCommands,
+               const GLubyte* commands,
+               GLsizei numCoords,
+               GLenum coordType,
+               const GLvoid* coords),
+              (path, numCommands, commands, numCoords, coordType, coords))
+VISIT_GL_CALL(PathParameterfCHROMIUM,
+              void,
+              (GLuint path, GLenum pname, GLfloat value),
+              (path, pname, value))
+VISIT_GL_CALL(PathParameteriCHROMIUM,
+              void,
+              (GLuint path, GLenum pname, GLint value),
+              (path, pname, value))
+VISIT_GL_CALL(PathStencilFuncCHROMIUM,
+              void,
+              (GLenum func, GLint ref, GLuint mask),
+              (func, ref, mask))
+VISIT_GL_CALL(StencilFillPathCHROMIUM,
+              void,
+              (GLuint path, GLenum fillMode, GLuint mask),
+              (path, fillMode, mask))
+VISIT_GL_CALL(StencilStrokePathCHROMIUM,
+              void,
+              (GLuint path, GLint reference, GLuint mask),
+              (path, reference, mask))
+VISIT_GL_CALL(CoverFillPathCHROMIUM,
+              void,
+              (GLuint path, GLenum coverMode),
+              (path, coverMode))
+VISIT_GL_CALL(CoverStrokePathCHROMIUM,
+              void,
+              (GLuint path, GLenum coverMode),
+              (path, coverMode))
+VISIT_GL_CALL(StencilThenCoverFillPathCHROMIUM,
+              void,
+              (GLuint path, GLenum fillMode, GLuint mask, GLenum coverMode),
+              (path, fillMode, mask, coverMode))
+VISIT_GL_CALL(StencilThenCoverStrokePathCHROMIUM,
+              void,
+              (GLuint path, GLint reference, GLuint mask, GLenum coverMode),
+              (path, reference, mask, coverMode))
+VISIT_GL_CALL(StencilFillPathInstancedCHROMIUM,
+              void,
+              (GLsizei numPaths,
+               GLenum pathNameType,
+               const GLvoid* paths,
+               GLuint pathBase,
+               GLenum fillMode,
+               GLuint mask,
+               GLenum transformType,
+               const GLfloat* transformValues),
+              (numPaths,
+               pathNameType,
+               paths,
+               pathBase,
+               fillMode,
+               mask,
+               transformType,
+               transformValues))
+VISIT_GL_CALL(StencilStrokePathInstancedCHROMIUM,
+              void,
+              (GLsizei numPaths,
+               GLenum pathNameType,
+               const GLvoid* paths,
+               GLuint pathBase,
+               GLint reference,
+               GLuint mask,
+               GLenum transformType,
+               const GLfloat* transformValues),
+              (numPaths,
+               pathNameType,
+               paths,
+               pathBase,
+               reference,
+               mask,
+               transformType,
+               transformValues))
+VISIT_GL_CALL(CoverFillPathInstancedCHROMIUM,
+              void,
+              (GLsizei numPaths,
+               GLenum pathNameType,
+               const GLvoid* paths,
+               GLuint pathBase,
+               GLenum coverMode,
+               GLenum transformType,
+               const GLfloat* transformValues),
+              (numPaths,
+               pathNameType,
+               paths,
+               pathBase,
+               coverMode,
+               transformType,
+               transformValues))
+VISIT_GL_CALL(CoverStrokePathInstancedCHROMIUM,
+              void,
+              (GLsizei numPaths,
+               GLenum pathNameType,
+               const GLvoid* paths,
+               GLuint pathBase,
+               GLenum coverMode,
+               GLenum transformType,
+               const GLfloat* transformValues),
+              (numPaths,
+               pathNameType,
+               paths,
+               pathBase,
+               coverMode,
+               transformType,
+               transformValues))
+VISIT_GL_CALL(StencilThenCoverFillPathInstancedCHROMIUM,
+              void,
+              (GLsizei numPaths,
+               GLenum pathNameType,
+               const GLvoid* paths,
+               GLuint pathBase,
+               GLenum fillMode,
+               GLuint mask,
+               GLenum coverMode,
+               GLenum transformType,
+               const GLfloat* transformValues),
+              (numPaths,
+               pathNameType,
+               paths,
+               pathBase,
+               fillMode,
+               mask,
+               coverMode,
+               transformType,
+               transformValues))
+VISIT_GL_CALL(StencilThenCoverStrokePathInstancedCHROMIUM,
+              void,
+              (GLsizei numPaths,
+               GLenum pathNameType,
+               const GLvoid* paths,
+               GLuint pathBase,
+               GLint reference,
+               GLuint mask,
+               GLenum coverMode,
+               GLenum transformType,
+               const GLfloat* transformValues),
+              (numPaths,
+               pathNameType,
+               paths,
+               pathBase,
+               reference,
+               mask,
+               coverMode,
+               transformType,
+               transformValues))
+VISIT_GL_CALL(BindFragmentInputLocationCHROMIUM,
+              void,
+              (GLuint program, GLint location, const char* name),
+              (program, location, name))
+VISIT_GL_CALL(ProgramPathFragmentInputGenCHROMIUM,
+              void,
+              (GLuint program,
+               GLint location,
+               GLenum genMode,
+               GLint components,
+               const GLfloat* coeffs),
+              (program, location, genMode, components, coeffs))
+VISIT_GL_CALL(GetGraphicsResetStatusKHR, GLenum, (), ())
+VISIT_GL_CALL(BlendBarrierKHR, void, (), ())
+VISIT_GL_CALL(ApplyScreenSpaceAntialiasingCHROMIUM, void, (), ())
+VISIT_GL_CALL(
+    BindFragDataLocationIndexedEXT,
+    void,
+    (GLuint program, GLuint colorNumber, GLuint index, const char* name),
+    (program, colorNumber, index, name))
+VISIT_GL_CALL(BindFragDataLocationEXT,
+              void,
+              (GLuint program, GLuint colorNumber, const char* name),
+              (program, colorNumber, name))
+VISIT_GL_CALL(GetFragDataIndexEXT,
+              GLint,
+              (GLuint program, const char* name),
+              (program, name))
diff --git a/third_party/usrsctp/usrsctp.gyp b/third_party/usrsctp/usrsctp.gyp
index b4a86b2..1ebb78a 100644
--- a/third_party/usrsctp/usrsctp.gyp
+++ b/third_party/usrsctp/usrsctp.gyp
@@ -130,15 +130,15 @@
           'defines': [
             '__Userspace_os_Windows',
             # Manually setting WINVER and _WIN32_WINNT is needed because Chrome
-            # sets WINVER to a newer version of  windows. But compiling usrsctp
-            # this way would is incompatible  with windows XP.
+            # sets WINVER to a newer version of Windows. But compiling usrsctp
+            # this way would be incompatible with Windows XP.
             'WINVER=0x0502',
             '_WIN32_WINNT=0x0502',
           ],
           'defines!': [
             # Remove Chrome's WINVER defines to avoid redefinition warnings.
-            'WINVER=0x0603',
-            '_WIN32_WINNT=0x0603',
+            'WINVER=0x0A00',
+            '_WIN32_WINNT=0x0A00',
           ],
           'cflags!': [ '/W3', '/WX' ],
           'cflags': [ '/w' ],
diff --git a/tools/android/android_tools.gyp b/tools/android/android_tools.gyp
index 9ae163c..92b2b71 100644
--- a/tools/android/android_tools.gyp
+++ b/tools/android/android_tools.gyp
@@ -17,7 +17,6 @@
         'md5sum/md5sum.gyp:md5sum',
         'memtrack_helper/memtrack_helper.gyp:memtrack_helper',
         'purge_ashmem/purge_ashmem.gyp:purge_ashmem',
-        'run_pie/run_pie.gyp:run_pie',
         '../../tools/telemetry/telemetry.gyp:*#host',
       ],
     },
diff --git a/tools/android/eclipse/.classpath b/tools/android/eclipse/.classpath
index 51d9f40c..eef7d41 100644
--- a/tools/android/eclipse/.classpath
+++ b/tools/android/eclipse/.classpath
@@ -29,7 +29,6 @@
     <classpathentry kind="src" path="chrome/android/java/src"/>
     <classpathentry kind="src" path="chrome/android/javatests/src"/>
     <classpathentry kind="src" path="chrome/android/sync_shell/javatests/src"/>
-    <classpathentry kind="src" path="chrome/android/uiautomator_tests/src"/>
     <classpathentry kind="src" path="chrome/android/junit/src"/>
     <classpathentry kind="src" path="chrome/test/android/javatests/src"/>
     <classpathentry kind="src" path="chrome/test/chromedriver/test/webview_shell/java/src"/>
@@ -95,23 +94,6 @@
     <classpathentry kind="src" path="out/Debug/android_webview_test_apk/gen"/>
     <classpathentry kind="src" path="out/Debug/chrome_public_apk/gen"/>
     <classpathentry kind="src" path="out/Debug/content_shell_apk/gen"/>
-    <classpathentry kind="src" path="out/Debug/gen/base/base_android_java_enums_srcjar__generate_enum/enums"/>
-    <classpathentry kind="src" path="out/Debug/gen/base/base_multidex_gen__apply_gcc/java_cpp_template"/>
-    <classpathentry kind="src" path="out/Debug/gen/base/base_native_libraries_gen__apply_gcc/java_cpp_template"/>
-    <classpathentry kind="src" path="out/Debug/gen/chrome/android/chrome_android_java_enums_srcjar__generate_enum/enums"/>
-    <classpathentry kind="src" path="out/Debug/gen/chrome/android/chrome_public_apk__native_libraries_java__apply_gcc/java_cpp_template"/>
-    <classpathentry kind="src" path="out/Debug/gen/chrome/android/resource_id_javagen__apply_gcc/java_cpp_template"/>
-    <classpathentry kind="src" path="out/Debug/gen/chrome/content_setting_javagen__generate_enum/enums"/>
-    <classpathentry kind="src" path="out/Debug/gen/chrome/content_settings_type_javagen__generate_enum/enums"/>
-    <classpathentry kind="src" path="out/Debug/gen/chrome/page_info_connection_type_javagen__generate_enum/enums"/>
-    <classpathentry kind="src" path="out/Debug/gen/components/bookmarks/common/android/bookmark_type_javagen__generate_enum/enums"/>
-    <classpathentry kind="src" path="out/Debug/gen/components/dom_distiller/android/dom_distiller_core_font_family_javagen__apply_gcc/java_cpp_template"/>
-    <classpathentry kind="src" path="out/Debug/gen/components/dom_distiller/android/dom_distiller_core_theme_javagen__apply_gcc/java_cpp_template"/>
-    <classpathentry kind="src" path="out/Debug/gen/components/enhanced_bookmarks/enhanced_bookmarks_java_enums_srcjar__generate_enum/enums"/>
-    <classpathentry kind="src" path="out/Debug/gen/components/offline_pages/offline_pages_enums_java__generate_enum/enums"/>
-    <classpathentry kind="src" path="out/Debug/gen/components/omnibox/browser/autocomplete_match_type_javagen__generate_enum/enums"/>
-    <classpathentry kind="src" path="out/Debug/gen/content/browser/accessibility/content_browser_accessibility_java_enums_srcjar__generate_enum/enums"/>
-    <classpathentry kind="src" path="out/Debug/gen/content/public/android/content_public_android_java_enums_srcjar__generate_enum/enums"/>
     <classpathentry kind="src" path="out/Debug/gen/enums/accessibility_java"/>
     <classpathentry kind="src" path="out/Debug/gen/enums/activity_type_ids_java"/>
     <classpathentry kind="src" path="out/Debug/gen/enums/android_resource_type_java"/>
@@ -165,10 +147,6 @@
     <classpathentry kind="src" path="out/Debug/gen/enums/web_input_event_java"/>
     <classpathentry kind="src" path="out/Debug/gen/enums/web_text_input_type"/>
     <classpathentry kind="src" path="out/Debug/gen/enums/window_open_disposition_java"/>
-    <classpathentry kind="src" path="out/Debug/gen/media/base/android/media_java_enums_srcjar__generate_enum/enums"/>
-    <classpathentry kind="src" path="out/Debug/gen/net/android/net_android_java_enums_srcjar__generate_enum/enums"/>
-    <classpathentry kind="src" path="out/Debug/gen/net/android/net_errors_java__apply_gcc/java_cpp_template"/>
-    <classpathentry kind="src" path="out/Debug/gen/sync/android/java_enums__generate_enum/enums"/>
     <classpathentry kind="src" path="out/Debug/gen/templates/base_native_libraries_gen"/>
     <classpathentry kind="src" path="out/Debug/gen/templates/chrome_version_java"/>
     <classpathentry kind="src" path="out/Debug/gen/templates/dom_distiller_core_font_family_java"/>
@@ -176,11 +154,6 @@
     <classpathentry kind="src" path="out/Debug/gen/templates/load_states_list"/>
     <classpathentry kind="src" path="out/Debug/gen/templates/net_errors_java"/>
     <classpathentry kind="src" path="out/Debug/gen/templates/resource_id_java"/>
-    <classpathentry kind="src" path="out/Debug/gen/third_party/WebKit/public/blink_headers_java_enums_srcjar__generate_enum/enums"/>
-    <classpathentry kind="src" path="out/Debug/gen/ui/accessibility/ax_enumerations_srcjar__generate_enum/enums"/>
-    <classpathentry kind="src" path="out/Debug/gen/ui/android/java_enums_srcjar__generate_enum/enums"/>
-    <classpathentry kind="src" path="out/Debug/gen/ui/touch_selection/ui_touch_handle_orientation_srcjar__generate_enum/enums"/>
-    <classpathentry kind="src" path="out/Debug/gen/ui/touch_selection/ui_touch_selection_enums_srcjar__generate_enum/enums"/>
     <classpathentry kind="src" path="out/Debug/java_mojo/device_battery_mojo_bindings/src"/>
     <classpathentry kind="src" path="out/Debug/java_mojo/mojo_public_test_interfaces_mojom/src"/>
     <classpathentry kind="src" path="out/Debug/java_proto/cacheinvalidation_proto_java/src"/>
@@ -202,12 +175,60 @@
     <classpathentry kind="lib" path="third_party/findbugs/lib/findbugs.jar"/>
     <classpathentry kind="lib" path="third_party/junit/src/lib/hamcrest-core-1.1.jar"/>
     <classpathentry kind="lib" path="third_party/robolectric/lib/robolectric-2.4-jar-with-dependencies.jar"/>
-    <classpathentry kind="lib" path="out/Debug/gen/chrome/android/chrome_public_apk/chrome_public_apk.jar"/>
     <classpathentry kind="lib" path="out/Debug/lib.java/cacheinvalidation_proto_java.jar"/>
     <classpathentry kind="lib" path="out/Debug/lib.java/content_java.jar"/>
     <classpathentry kind="lib" path="out/Debug/lib.java/jsr_305_javalib.jar"/>
     <classpathentry kind="lib" path="out/Debug/lib.java/net_java.jar"/>
-    <classpathentry kind="output" path="out/bin"/>
+
+    <!-- GN: R (resources) and NativeLibraries classes. -->
+    <classpathentry kind="lib" path="out/Debug/gen/chrome/android/chrome_public_apk/chrome_public_apk.jar"/>
+
+    <!-- GN: library jars, includes generated Java files. -->
+    <classpathentry kind="lib" path="out/Debug/lib.java/android_webview/android_webview_java.jar"/>
+    <classpathentry kind="lib" path="out/Debug/lib.java/base/base_java.jar"/>
+    <classpathentry kind="lib" path="out/Debug/lib.java/chrome/android/chrome_java.jar"/>
+    <classpathentry kind="lib" path="out/Debug/lib.java/chrome/android/document_tab_model_info_proto_java.jar"/>
+    <classpathentry kind="lib" path="out/Debug/lib.java/components/bookmarks/common/android/bookmarks_java.jar"/>
+    <classpathentry kind="lib" path="out/Debug/lib.java/components/dom_distiller/android/dom_distiller_content_java.jar"/>
+    <classpathentry kind="lib" path="out/Debug/lib.java/components/dom_distiller/android/dom_distiller_core_java.jar"/>
+    <classpathentry kind="lib" path="out/Debug/lib.java/components/external_video_surface/java.jar"/>
+    <classpathentry kind="lib" path="out/Debug/lib.java/components/gcm_driver/android/gcm_driver_java.jar"/>
+    <classpathentry kind="lib" path="out/Debug/lib.java/components/invalidation/impl/java.jar"/>
+    <classpathentry kind="lib" path="out/Debug/lib.java/components/invalidation/impl/proto_java.jar"/>
+    <classpathentry kind="lib" path="out/Debug/lib.java/components/navigation_interception/android/navigation_interception_java.jar"/>
+    <classpathentry kind="lib" path="out/Debug/lib.java/components/policy/android/policy_java.jar"/>
+    <classpathentry kind="lib" path="out/Debug/lib.java/components/precache/android/precache_java.jar"/>
+    <classpathentry kind="lib" path="out/Debug/lib.java/components/safe_json/android/safe_json_java.jar"/>
+    <classpathentry kind="lib" path="out/Debug/lib.java/components/service_tab_launcher/service_tab_launcher_java.jar"/>
+    <classpathentry kind="lib" path="out/Debug/lib.java/components/signin/core/browser/android/java.jar"/>
+    <classpathentry kind="lib" path="out/Debug/lib.java/components/variations/android/variations_java.jar"/>
+    <classpathentry kind="lib" path="out/Debug/lib.java/components/web_contents_delegate_android/web_contents_delegate_android_java.jar"/>
+    <classpathentry kind="lib" path="out/Debug/lib.java/content/public/android/content_java.jar"/>
+    <classpathentry kind="lib" path="out/Debug/lib.java/device/battery/android/battery_monitor_android.jar"/>
+    <classpathentry kind="lib" path="out/Debug/lib.java/device/battery/mojo_bindings_java.jar"/>
+    <classpathentry kind="lib" path="out/Debug/lib.java/device/bluetooth/java.jar"/>
+    <classpathentry kind="lib" path="out/Debug/lib.java/device/vibration/android/vibration_manager_android.jar"/>
+    <classpathentry kind="lib" path="out/Debug/lib.java/device/vibration/mojo_bindings_java.jar"/>
+    <classpathentry kind="lib" path="out/Debug/lib.java/media/base/android/media_java.jar"/>
+    <classpathentry kind="lib" path="out/Debug/lib.java/media/midi/midi_java.jar"/>
+    <classpathentry kind="lib" path="out/Debug/lib.java/mojo/android/system_java.jar"/>
+    <classpathentry kind="lib" path="out/Debug/lib.java/mojo/public/java/bindings.jar"/>
+    <classpathentry kind="lib" path="out/Debug/lib.java/mojo/public/java/system.jar"/>
+    <classpathentry kind="lib" path="out/Debug/lib.java/net/android/net_java.jar"/>
+    <classpathentry kind="lib" path="out/Debug/lib.java/printing/printing_java.jar"/>
+    <classpathentry kind="lib" path="out/Debug/lib.java/sync/android/sync_java.jar"/>
+    <classpathentry kind="lib" path="out/Debug/lib.java/sync/test_support_sync_proto_java.jar"/>
+    <classpathentry kind="lib" path="out/Debug/lib.java/third_party/android_data_chart/android_data_chart_java.jar"/>
+    <classpathentry kind="lib" path="out/Debug/lib.java/third_party/android_media/android_media_java.jar"/>
+    <classpathentry kind="lib" path="out/Debug/lib.java/third_party/android_protobuf/protobuf_nano_javalib.jar"/>
+    <classpathentry kind="lib" path="out/Debug/lib.java/third_party/android_swipe_refresh/android_swipe_refresh_java.jar"/>
+    <classpathentry kind="lib" path="out/Debug/lib.java/third_party/cacheinvalidation/cacheinvalidation_javalib.jar"/>
+    <classpathentry kind="lib" path="out/Debug/lib.java/third_party/cacheinvalidation/cacheinvalidation_proto_java.jar"/>
+    <classpathentry kind="lib" path="out/Debug/lib.java/third_party/cardboard-java/cardboard-java.jar"/>
+    <classpathentry kind="lib" path="out/Debug/lib.java/third_party/gif_player/gif_player_java.jar"/>
+    <classpathentry kind="lib" path="out/Debug/lib.java/third_party/WebKit/public/blink_headers_java.jar"/>
+    <classpathentry kind="lib" path="out/Debug/lib.java/ui/accessibility/ui_accessibility_java.jar"/>
+    <classpathentry kind="lib" path="out/Debug/lib.java/ui/android/ui_java.jar"/>
 
     <!-- {% block additional_entries %} -->
     <!-- When this file is processed as a jinja2 template, additional
diff --git a/tools/android/heap_profiler/heap_dump.c b/tools/android/heap_profiler/heap_dump.c
index 5d468da9..9df78c5 100644
--- a/tools/android/heap_profiler/heap_dump.c
+++ b/tools/android/heap_profiler/heap_dump.c
@@ -40,6 +40,7 @@
 #include <unistd.h>
 #include <sys/ptrace.h>
 #include <sys/stat.h>
+#include <sys/wait.h>
 
 #include "tools/android/heap_profiler/heap_profiler.h"
 
@@ -234,8 +235,6 @@
 static ssize_t read_safe(int fd, void* buf, size_t count) {
   ssize_t res;
   size_t bytes_read = 0;
-  if (count < 0)
-    return -1;
   do {
     do {
       res = read(fd, buf + bytes_read, count - bytes_read);
diff --git a/tools/android/run_pie/run_pie.c b/tools/android/run_pie/run_pie.c
deleted file mode 100644
index ee1a622..0000000
--- a/tools/android/run_pie/run_pie.c
+++ /dev/null
@@ -1,68 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <dlfcn.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/prctl.h>
-#include <unistd.h>
-
-// This is a wrapper to run position independent executables on Android ICS,
-// where the linker doesn't support PIE. This requires the PIE binaries to be
-// built with CFLAGS +=-fvisibility=default -fPIE, and LDFLAGS += -rdynamic -pie
-// such that the main() symbol remains exported and can be dlsym-ed.
-
-#define ERR_PREFIX "[PIE Loader] "
-
-typedef int (*main_t)(int, char**);
-
-
-int main(int argc, char** argv) {
-  if (argc < 2) {
-    printf("Usage: %s path_to_pie_executable [args]\n", argv[0]);
-    return -1;
-  }
-
-  // Shift left the argv[]. argv is what /proc/PID/cmdline prints out. In turn
-  // cmdline is what Android "ps" prints out. In turn "ps" is what many scripts
-  // look for to decide which processes to kill / killall.
-  int i;
-  char* next_argv_start = argv[0];
-  for (i = 1; i < argc; ++i) {
-    const size_t argv_len = strlen(argv[i]) + 1;
-    memcpy(argv[i - 1], argv[i], argv_len);
-    next_argv_start += argv_len;
-    argv[i] = next_argv_start;
-  }
-  argv[argc - 1] = NULL;  // The last argv must be a NULL ptr.
-
-  // Set also the proc name accordingly (/proc/PID/comm).
-  prctl(PR_SET_NAME, (long) argv[0]);
-
-  // dlopen should not fail, unless:
-  // - The target binary does not exists:
-  // - The dependent .so libs cannot be loaded.
-  // In both cases, just bail out with an explicit error message.
-  void* handle = dlopen(argv[0], RTLD_NOW);
-  if (handle == NULL) {
-    printf(ERR_PREFIX "dlopen() failed: %s.\n", dlerror());
-    return -1;
-  }
-
-  main_t pie_main = (main_t) dlsym(handle, "main");
-  if (pie_main) {
-    return pie_main(argc - 1, argv);
-  }
-
-  // If we reached this point dlsym failed, very likely because the target
-  // binary has not been compiled with the proper CFLAGS / LDFLAGS.
-  // At this point the most sensible thing to do is running that normally
-  // via exec and hope that the target binary wasn't a PIE.
-  execv(argv[0], argv);
-
-  // exevc is supposed to never return, unless it fails.
-  printf(ERR_PREFIX "Both dlsym() and the execv() fallback failed.\n");
-  perror("execv");
-  return -1;
-}
diff --git a/tools/android/run_pie/run_pie.gyp b/tools/android/run_pie/run_pie.gyp
deleted file mode 100644
index 75850f4..0000000
--- a/tools/android/run_pie/run_pie.gyp
+++ /dev/null
@@ -1,49 +0,0 @@
-# Copyright 2014 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-{
-  'targets': [
-    {
-      'target_name': 'run_pie-unstripped',
-      'type': 'executable',
-      'sources': [
-        'run_pie.c',
-      ],
-      # See crbug.com/373219. This is the only Android executable which must be
-      # non PIE.
-      'cflags!': [
-        '-fPIE',
-      ],
-      'ldflags!': [
-        '-pie',
-      ],
-      # Don't inherit unneeded dependencies on libc++, so the binary remains
-      # self-contained also in component=shared_library builds.
-      'libraries!': [
-        '-l<(android_libcpp_library)',
-      ],
-    },
-    {
-      'target_name': 'run_pie',
-      'type': 'none',
-      'dependencies': [
-        'run_pie-unstripped',
-      ],
-      'actions': [
-        {
-          'action_name': 'strip_run_pie',
-          'inputs': ['<(PRODUCT_DIR)/run_pie-unstripped'],
-          'outputs': ['<(PRODUCT_DIR)/run_pie'],
-          'action': [
-            '<(android_strip)',
-            '--strip-unneeded',
-            '<@(_inputs)',
-            '-o',
-            '<@(_outputs)',
-          ],
-        },
-      ],
-    },
-  ],
-}
diff --git a/tools/clang/pass_to_move/CMakeLists.txt b/tools/clang/pass_to_move/CMakeLists.txt
new file mode 100644
index 0000000..b3ceee1
--- /dev/null
+++ b/tools/clang/pass_to_move/CMakeLists.txt
@@ -0,0 +1,27 @@
+set(LLVM_LINK_COMPONENTS
+  BitReader
+  MCParser
+  Option
+  X86AsmParser
+  )
+
+add_llvm_executable(pass_to_move
+  PassToMove.cpp
+  )
+
+target_link_libraries(pass_to_move
+  clangAST
+  clangASTMatchers
+  clangAnalysis
+  clangBasic
+  clangDriver
+  clangEdit
+  clangFrontend
+  clangLex
+  clangParse
+  clangSema
+  clangSerialization
+  clangTooling
+  )
+
+cr_install(TARGETS pass_to_move RUNTIME DESTINATION bin)
diff --git a/tools/clang/pass_to_move/PassToMove.cpp b/tools/clang/pass_to_move/PassToMove.cpp
new file mode 100644
index 0000000..90a94ce
--- /dev/null
+++ b/tools/clang/pass_to_move/PassToMove.cpp
@@ -0,0 +1,104 @@
+// 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.
+//
+// Clang tool to change calls to scoper::Pass() to just use std::move().
+
+#include <memory>
+#include <string>
+
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/ASTMatchers/ASTMatchersMacros.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Frontend/FrontendActions.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Tooling/CommonOptionsParser.h"
+#include "clang/Tooling/Refactoring.h"
+#include "clang/Tooling/Tooling.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/TargetSelect.h"
+
+using namespace clang::ast_matchers;
+using clang::tooling::CommonOptionsParser;
+using clang::tooling::Replacement;
+using clang::tooling::Replacements;
+using llvm::StringRef;
+
+namespace {
+
+class RewriterCallback : public MatchFinder::MatchCallback {
+ public:
+  explicit RewriterCallback(Replacements* replacements)
+      : replacements_(replacements) {}
+  virtual void run(const MatchFinder::MatchResult& result) override;
+
+ private:
+  Replacements* const replacements_;
+};
+
+void RewriterCallback::run(const MatchFinder::MatchResult& result) {
+  const clang::Expr* arg = result.Nodes.getNodeAs<clang::Expr>("arg");
+  clang::CharSourceRange arg_range = clang::CharSourceRange::getTokenRange(
+      result.SourceManager->getSpellingLoc(arg->getLocStart()),
+      result.SourceManager->getSpellingLoc(arg->getLocEnd()));
+  llvm::Twine new_source_text =
+      llvm::Twine("std::move(")
+          .concat(clang::Lexer::getSourceText(arg_range, *result.SourceManager,
+                                              result.Context->getLangOpts()))
+          .concat(")");
+  // Replace the entire original expression with std::move(arg).
+  const clang::Expr* expr = result.Nodes.getNodeAs<clang::Expr>("expr");
+  clang::CharSourceRange expr_range = clang::CharSourceRange::getTokenRange(
+      result.SourceManager->getSpellingLoc(expr->getLocStart()),
+      result.SourceManager->getSpellingLoc(expr->getLocEnd()));
+  replacements_->emplace(*result.SourceManager, expr_range,
+                         new_source_text.str());
+}
+
+}  // namespace
+
+static llvm::cl::extrahelp common_help(CommonOptionsParser::HelpMessage);
+
+int main(int argc, const char* argv[]) {
+  // TODO(dcheng): Clang tooling should do this itself.
+  // http://llvm.org/bugs/show_bug.cgi?id=21627
+  llvm::InitializeNativeTarget();
+  llvm::InitializeNativeTargetAsmParser();
+  llvm::cl::OptionCategory category(
+      "C++11 modernization: change scoped::Pass() to std::move()");
+  CommonOptionsParser options(argc, argv, category);
+  clang::tooling::ClangTool tool(options.getCompilations(),
+                                 options.getSourcePathList());
+
+  MatchFinder match_finder;
+  Replacements replacements;
+
+  auto pass_matcher = id(
+      "expr",
+      cxxMemberCallExpr(argumentCountIs(0),
+                        hasDeclaration(functionDecl(
+                            hasName("Pass"), returns(rValueReferenceType()))),
+                        on(id("arg", expr()))));
+  RewriterCallback callback(&replacements);
+  match_finder.addMatcher(pass_matcher, &callback);
+
+  std::unique_ptr<clang::tooling::FrontendActionFactory> factory =
+      clang::tooling::newFrontendActionFactory(&match_finder);
+  int result = tool.run(factory.get());
+  if (result != 0)
+    return result;
+
+  // Serialization format is documented in tools/clang/scripts/run_tool.py
+  llvm::outs() << "==== BEGIN EDITS ====\n";
+  for (const auto& r : replacements) {
+    std::string replacement_text = r.getReplacementText().str();
+    std::replace(replacement_text.begin(), replacement_text.end(), '\n', '\0');
+    llvm::outs() << "r:::" << r.getFilePath() << ":::" << r.getOffset()
+                 << ":::" << r.getLength() << ":::" << replacement_text << "\n";
+  }
+  llvm::outs() << "==== END EDITS ====\n";
+
+  return 0;
+}
diff --git a/tools/clang/pass_to_move/tests/test-expected.cc b/tools/clang/pass_to_move/tests/test-expected.cc
new file mode 100644
index 0000000..f7d6d3f
--- /dev/null
+++ b/tools/clang/pass_to_move/tests/test-expected.cc
@@ -0,0 +1,33 @@
+// 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.
+
+struct A {
+  A&& Pass();
+};
+
+struct B {
+  B& Pass();
+};
+
+struct C {
+  A a;
+};
+
+struct D {
+  D&& NotPass();
+};
+
+void F() {
+  A a1;
+  A a2 = std::move(a1);
+
+  B b1;
+  B b2 = b2.Pass();
+
+  C c;
+  A a3 = std::move(c.a);
+
+  D d1;
+  D d2 = d1.NotPass();
+}
diff --git a/tools/clang/pass_to_move/tests/test-original.cc b/tools/clang/pass_to_move/tests/test-original.cc
new file mode 100644
index 0000000..7024aa7
--- /dev/null
+++ b/tools/clang/pass_to_move/tests/test-original.cc
@@ -0,0 +1,33 @@
+// 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.
+
+struct A {
+  A&& Pass();
+};
+
+struct B {
+  B& Pass();
+};
+
+struct C {
+  A a;
+};
+
+struct D {
+  D&& NotPass();
+};
+
+void F() {
+  A a1;
+  A a2 = a1.Pass();
+
+  B b1;
+  B b2 = b2.Pass();
+
+  C c;
+  A a3 = c.a.Pass();
+
+  D d1;
+  D d2 = d1.NotPass();
+}
diff --git a/tools/clang/plugins/README.chromium b/tools/clang/plugins/README.chromium
index a2ce0ff..1c6f0c01 100644
--- a/tools/clang/plugins/README.chromium
+++ b/tools/clang/plugins/README.chromium
@@ -1,4 +1,4 @@
 Documentation for this code is:
 
-- http://code.google.com/p/chromium/wiki/Clang
-- http://code.google.com/p/chromium/wiki/WritingClangPlugins
+- https://chromium.googlesource.com/chromium/src/+/master/docs/clang.md
+- https://chromium.googlesource.com/chromium/src/+/master/docs/writing_clang_plugins.md
diff --git a/tools/clang/scripts/update.py b/tools/clang/scripts/update.py
index 03f484c6..db7df2ac 100755
--- a/tools/clang/scripts/update.py
+++ b/tools/clang/scripts/update.py
@@ -63,7 +63,8 @@
 LIBCXXABI_DIR = os.path.join(LLVM_DIR, 'projects', 'libcxxabi')
 LLVM_BUILD_TOOLS_DIR = os.path.abspath(
     os.path.join(LLVM_DIR, '..', 'llvm-build-tools'))
-STAMP_FILE = os.path.join(LLVM_DIR, '..', 'llvm-build', 'cr_build_revision')
+STAMP_FILE = os.path.normpath(
+    os.path.join(LLVM_DIR, '..', 'llvm-build', 'cr_build_revision'))
 BINUTILS_DIR = os.path.join(THIRD_PARTY_DIR, 'binutils')
 VERSION = '3.8.0'
 ANDROID_NDK_DIR = os.path.join(
diff --git a/tools/generate_library_loader/generate_library_loader.gni b/tools/generate_library_loader/generate_library_loader.gni
index 24f753b..c714c12 100644
--- a/tools/generate_library_loader/generate_library_loader.gni
+++ b/tools/generate_library_loader/generate_library_loader.gni
@@ -63,7 +63,7 @@
       output_cc,
       output_h,
     ]
-    deps = [
+    public_deps = [
       ":${target_name}_loader",
     ]
   }
diff --git a/tools/gn/docs/reference.md b/tools/gn/docs/reference.md
index a180d88..97f12f2 100644
--- a/tools/gn/docs/reference.md
+++ b/tools/gn/docs/reference.md
@@ -1431,7 +1431,7 @@
 
   "root_out_dir"
       The root of the output file tree for the target. This will
-      match the value of the "root_gen_dir" variable when inside that
+      match the value of the "root_out_dir" variable when inside that
       target's declaration.
 
   "label_no_toolchain"
@@ -3306,20 +3306,13 @@
 
 
 ```
-## **cflags***: Flags passed to the C compiler.
+## **asmflags**: Flags passed to the assembler.
 
 ```
   A list of strings.
 
-  "cflags" are passed to all invocations of the C, C++, Objective C,
-  and Objective C++ compilers.
-
-  To target one of these variants individually, use "cflags_c",
-  "cflags_cc", "cflags_objc", and "cflags_objcc",
-  respectively.
-
-  These variant-specific versions of cflags* will be appended to the
-  "cflags".
+  "asmflags" are passed to any invocation of a tool that takes an
+  .asm or .S file as input.
 
 ```
 
@@ -3352,10 +3345,10 @@
 
   To target one of these variants individually, use "cflags_c",
   "cflags_cc", "cflags_objc", and "cflags_objcc",
-  respectively.
+  respectively. These variant-specific versions of cflags* will be
+  appended on the compiler command line after "cflags".
 
-  These variant-specific versions of cflags* will be appended to the
-  "cflags".
+  See also "asmflags" for flags for assembly-language files.
 
 ```
 
@@ -3388,10 +3381,10 @@
 
   To target one of these variants individually, use "cflags_c",
   "cflags_cc", "cflags_objc", and "cflags_objcc",
-  respectively.
+  respectively. These variant-specific versions of cflags* will be
+  appended on the compiler command line after "cflags".
 
-  These variant-specific versions of cflags* will be appended to the
-  "cflags".
+  See also "asmflags" for flags for assembly-language files.
 
 ```
 
@@ -3424,10 +3417,10 @@
 
   To target one of these variants individually, use "cflags_c",
   "cflags_cc", "cflags_objc", and "cflags_objcc",
-  respectively.
+  respectively. These variant-specific versions of cflags* will be
+  appended on the compiler command line after "cflags".
 
-  These variant-specific versions of cflags* will be appended to the
-  "cflags".
+  See also "asmflags" for flags for assembly-language files.
 
 ```
 
@@ -3460,10 +3453,46 @@
 
   To target one of these variants individually, use "cflags_c",
   "cflags_cc", "cflags_objc", and "cflags_objcc",
-  respectively.
+  respectively. These variant-specific versions of cflags* will be
+  appended on the compiler command line after "cflags".
 
-  These variant-specific versions of cflags* will be appended to the
-  "cflags".
+  See also "asmflags" for flags for assembly-language files.
+
+```
+
+### **Ordering of flags and values**
+
+```
+  1. Those set on the current target (not in a config).
+  2. Those set on the "configs" on the target in order that the
+     configs appear in the list.
+  3. Those set on the "all_dependent_configs" on the target in order
+     that the configs appear in the list.
+  4. Those set on the "public_configs" on the target in order that
+     those configs appear in the list.
+  5. all_dependent_configs pulled from dependencies, in the order of
+     the "deps" list. This is done recursively. If a config appears
+     more than once, only the first occurance will be used.
+  6. public_configs pulled from dependencies, in the order of the
+     "deps" list. If a dependency is public, they will be applied
+     recursively.
+
+
+```
+## **cflags***: Flags passed to the C compiler.
+
+```
+  A list of strings.
+
+  "cflags" are passed to all invocations of the C, C++, Objective C,
+  and Objective C++ compilers.
+
+  To target one of these variants individually, use "cflags_c",
+  "cflags_cc", "cflags_objc", and "cflags_objcc",
+  respectively. These variant-specific versions of cflags* will be
+  appended on the compiler command line after "cflags".
+
+  See also "asmflags" for flags for assembly-language files.
 
 ```
 
diff --git a/tools/gn/filesystem_utils.cc b/tools/gn/filesystem_utils.cc
index a3455fd..5905cdb 100644
--- a/tools/gn/filesystem_utils.cc
+++ b/tools/gn/filesystem_utils.cc
@@ -377,7 +377,7 @@
 #endif
 }
 
-void NormalizePath(std::string* path) {
+void NormalizePath(std::string* path, const base::StringPiece& source_root) {
   char* pathbuf = path->empty() ? nullptr : &(*path)[0];
 
   // top_index is the first character we can modify in the path. Anything
@@ -433,9 +433,48 @@
                 // up more levels.  Otherwise "../.." would collapse to
                 // nothing.
                 top_index = dest_i;
+              } else if (top_index == 2 && !source_root.empty()) {
+                // |path| was passed in as a source-absolute path. Prepend
+                // |source_root| to make |path| absolute. |source_root| must not
+                // end with a slash unless we are at root.
+                DCHECK(source_root.size() == 1u ||
+                       !IsSlash(source_root[source_root.size() - 1u]));
+                size_t source_root_len = source_root.size();
+
+#if defined(OS_WIN)
+                // On Windows, if the source_root does not start with a slash,
+                // append one here for consistency.
+                if (!IsSlash(source_root[0])) {
+                  path->insert(0, "/" + source_root.as_string());
+                  source_root_len++;
+                } else {
+                  path->insert(0, source_root.data(), source_root_len);
+                }
+
+                // Normalize slashes in source root portion.
+                for (size_t i = 0; i < source_root_len; ++i) {
+                  if ((*path)[i] == '\\')
+                    (*path)[i] = '/';
+                }
+#else
+                path->insert(0, source_root.data(), source_root_len);
+#endif
+
+                // |path| is now absolute, so |top_index| is 1. |dest_i| and
+                // |src_i| should be incremented to keep the same relative
+                // position. Comsume the leading "//" by decrementing |dest_i|.
+                top_index = 1;
+                pathbuf = &(*path)[0];
+                dest_i += source_root_len - 2;
+                src_i += source_root_len;
+
+                // Just find the previous slash or the beginning of input.
+                while (dest_i > 0 && !IsSlash(pathbuf[dest_i - 1]))
+                  dest_i--;
               }
-              // Otherwise we're at the beginning of an absolute path. Don't
-              // allow ".." to go up another level and just eat it.
+              // Otherwise we're at the beginning of a system-absolute path, or
+              // a source-absolute path for which we don't know the absolute
+              // path. Don't allow ".." to go up another level, and just eat it.
             } else {
               // Just find the previous slash or the beginning of input.
               while (dest_i > 0 && !IsSlash(pathbuf[dest_i - 1]))
diff --git a/tools/gn/filesystem_utils.h b/tools/gn/filesystem_utils.h
index 4d71ca7b..e6a17ab 100644
--- a/tools/gn/filesystem_utils.h
+++ b/tools/gn/filesystem_utils.h
@@ -111,8 +111,15 @@
                                         const base::StringPiece& path,
                                         std::string* dest);
 
-// Collapses "." and sequential "/"s and evaluates "..".
-void NormalizePath(std::string* path);
+// Collapses "." and sequential "/"s and evaluates "..". |path| may be
+// system-absolute, source-absolute, or relative. If |path| is source-absolute
+// and |source_root| is non-empty, |path| may be system absolute after this
+// function returns, if |path| references the filesystem outside of
+// |source_root| (ex. path = "//.."). In this case on Windows, |path| will have
+// a leading slash. Otherwise, |path| will retain its relativity. |source_root|
+// must not end with a slash.
+void NormalizePath(std::string* path,
+                   const base::StringPiece& source_root = base::StringPiece());
 
 // Converts slashes to backslashes for Windows. Keeps the string unchanged
 // for other systems.
diff --git a/tools/gn/filesystem_utils_unittest.cc b/tools/gn/filesystem_utils_unittest.cc
index 9f89512..27ccab2 100644
--- a/tools/gn/filesystem_utils_unittest.cc
+++ b/tools/gn/filesystem_utils_unittest.cc
@@ -204,7 +204,7 @@
   NormalizePath(&input);
   EXPECT_EQ("../bar", input);
 
-  input = "/../foo";  // Don't go aboe the root dir.
+  input = "/../foo";  // Don't go above the root dir.
   NormalizePath(&input);
   EXPECT_EQ("/foo", input);
 
@@ -241,6 +241,134 @@
   input = "//foo/bar/";
   NormalizePath(&input);
   EXPECT_EQ("//foo/bar/", input);
+
+#if defined(OS_WIN)
+  // Go above and outside of the source root.
+  input = "//../foo";
+  NormalizePath(&input, "/C:/source/root");
+  EXPECT_EQ("/C:/source/foo", input);
+
+  input = "//../foo";
+  NormalizePath(&input, "C:\\source\\root");
+  EXPECT_EQ("/C:/source/foo", input);
+
+  input = "//../";
+  NormalizePath(&input, "/C:/source/root");
+  EXPECT_EQ("/C:/source/", input);
+
+  input = "//../foo.txt";
+  NormalizePath(&input, "/C:/source/root");
+  EXPECT_EQ("/C:/source/foo.txt", input);
+
+  input = "//../foo/bar/";
+  NormalizePath(&input, "/C:/source/root");
+  EXPECT_EQ("/C:/source/foo/bar/", input);
+
+  // Go above and back into the source root. This should return a system-
+  // absolute path. We could arguably return this as a source-absolute path,
+  // but that would require additional handling to account for a rare edge
+  // case.
+  input = "//../root/foo";
+  NormalizePath(&input, "/C:/source/root");
+  EXPECT_EQ("/C:/source/root/foo", input);
+
+  input = "//../root/foo/bar/";
+  NormalizePath(&input, "/C:/source/root");
+  EXPECT_EQ("/C:/source/root/foo/bar/", input);
+
+  // Stay inside the source root
+  input = "//foo/bar";
+  NormalizePath(&input, "/C:/source/root");
+  EXPECT_EQ("//foo/bar", input);
+
+  input = "//foo/bar/";
+  NormalizePath(&input, "/C:/source/root");
+  EXPECT_EQ("//foo/bar/", input);
+
+  // The path should not go above the system root. Note that on Windows, this
+  // will consume the drive (C:).
+  input = "//../../../../../foo/bar";
+  NormalizePath(&input, "/C:/source/root");
+  EXPECT_EQ("/foo/bar", input);
+
+  // Test when the source root is the letter drive.
+  input = "//../foo";
+  NormalizePath(&input, "/C:");
+  EXPECT_EQ("/foo", input);
+
+  input = "//../foo";
+  NormalizePath(&input, "C:");
+  EXPECT_EQ("/foo", input);
+
+  input = "//../foo";
+  NormalizePath(&input, "/");
+  EXPECT_EQ("/foo", input);
+
+  input = "//../";
+  NormalizePath(&input, "\\C:");
+  EXPECT_EQ("/", input);
+
+  input = "//../foo.txt";
+  NormalizePath(&input, "/C:");
+  EXPECT_EQ("/foo.txt", input);
+#else
+  // Go above and outside of the source root.
+  input = "//../foo";
+  NormalizePath(&input, "/source/root");
+  EXPECT_EQ("/source/foo", input);
+
+  input = "//../";
+  NormalizePath(&input, "/source/root");
+  EXPECT_EQ("/source/", input);
+
+  input = "//../foo.txt";
+  NormalizePath(&input, "/source/root");
+  EXPECT_EQ("/source/foo.txt", input);
+
+  input = "//../foo/bar/";
+  NormalizePath(&input, "/source/root");
+  EXPECT_EQ("/source/foo/bar/", input);
+
+  // Go above and back into the source root. This should return a system-
+  // absolute path. We could arguably return this as a source-absolute path,
+  // but that would require additional handling to account for a rare edge
+  // case.
+  input = "//../root/foo";
+  NormalizePath(&input, "/source/root");
+  EXPECT_EQ("/source/root/foo", input);
+
+  input = "//../root/foo/bar/";
+  NormalizePath(&input, "/source/root");
+  EXPECT_EQ("/source/root/foo/bar/", input);
+
+  // Stay inside the source root
+  input = "//foo/bar";
+  NormalizePath(&input, "/source/root");
+  EXPECT_EQ("//foo/bar", input);
+
+  input = "//foo/bar/";
+  NormalizePath(&input, "/source/root");
+  EXPECT_EQ("//foo/bar/", input);
+
+  // The path should not go above the system root.
+  input = "//../../../../../foo/bar";
+  NormalizePath(&input, "/source/root");
+  EXPECT_EQ("/foo/bar", input);
+
+  // Test when the source root is the system root.
+  input = "//../foo/bar/";
+  NormalizePath(&input, "/");
+  EXPECT_EQ("/foo/bar/", input);
+
+  input = "//../";
+  NormalizePath(&input, "/");
+  EXPECT_EQ("/", input);
+
+  input = "//../foo.txt";
+  NormalizePath(&input, "/");
+  EXPECT_EQ("/foo.txt", input);
+
+#endif
 }
 
 TEST(FilesystemUtils, RebasePath) {
diff --git a/tools/gn/function_rebase_path_unittest.cc b/tools/gn/function_rebase_path_unittest.cc
index bed5663..456d4fb8 100644
--- a/tools/gn/function_rebase_path_unittest.cc
+++ b/tools/gn/function_rebase_path_unittest.cc
@@ -43,7 +43,7 @@
   EXPECT_EQ("../..", RebaseOne(scope, "../..", "//out/Debug", "."));
   EXPECT_EQ("../../", RebaseOne(scope, "../../", "//out/Debug", "."));
 
-  // We don't allow going above the root source dir.
+  // Without a source root defined, we cannot move out of the source tree.
   EXPECT_EQ("../..", RebaseOne(scope, "../../..", "//out/Debug", "."));
 
   // Source-absolute input paths.
@@ -62,19 +62,36 @@
 
   // Test system path output.
 #if defined(OS_WIN)
-  setup.build_settings()->SetRootPath(base::FilePath(L"C:/source"));
-  EXPECT_EQ("C:/source", RebaseOne(scope, ".", "", "//"));
-  EXPECT_EQ("C:/source/", RebaseOne(scope, "//", "", "//"));
-  EXPECT_EQ("C:/source/foo", RebaseOne(scope, "foo", "", "//"));
-  EXPECT_EQ("C:/source/foo/", RebaseOne(scope, "foo/", "", "//"));
-  EXPECT_EQ("C:/source/tools/gn/foo", RebaseOne(scope, "foo", "", "."));
+  setup.build_settings()->SetRootPath(base::FilePath(L"C:/path/to/src"));
+  EXPECT_EQ("C:/path/to/src", RebaseOne(scope, ".", "", "//"));
+  EXPECT_EQ("C:/path/to/src/", RebaseOne(scope, "//", "", "//"));
+  EXPECT_EQ("C:/path/to/src/foo", RebaseOne(scope, "foo", "", "//"));
+  EXPECT_EQ("C:/path/to/src/foo/", RebaseOne(scope, "foo/", "", "//"));
+  EXPECT_EQ("C:/path/to/src/tools/gn/foo", RebaseOne(scope, "foo", "", "."));
+  EXPECT_EQ("C:/path/to/other/tools",
+            RebaseOne(scope, "//../other/tools", "", "//"));
+  EXPECT_EQ("C:/path/to/src/foo/bar",
+            RebaseOne(scope, "//../src/foo/bar", "", "//"));
+  EXPECT_EQ("C:/path/to", RebaseOne(scope, "//..", "", "//"));
+  EXPECT_EQ("C:/path", RebaseOne(scope, "../../../..", "", "."));
+  EXPECT_EQ("C:/path/to/external/dir/",
+            RebaseOne(scope, "//../external/dir/", "", "//"));
+
 #else
-  setup.build_settings()->SetRootPath(base::FilePath("/source"));
-  EXPECT_EQ("/source", RebaseOne(scope, ".", "", "//"));
-  EXPECT_EQ("/source/", RebaseOne(scope, "//", "", "//"));
-  EXPECT_EQ("/source/foo", RebaseOne(scope, "foo", "", "//"));
-  EXPECT_EQ("/source/foo/", RebaseOne(scope, "foo/", "", "//"));
-  EXPECT_EQ("/source/tools/gn/foo", RebaseOne(scope, "foo", "", "."));
+  setup.build_settings()->SetRootPath(base::FilePath("/path/to/src"));
+  EXPECT_EQ("/path/to/src", RebaseOne(scope, ".", "", "//"));
+  EXPECT_EQ("/path/to/src/", RebaseOne(scope, "//", "", "//"));
+  EXPECT_EQ("/path/to/src/foo", RebaseOne(scope, "foo", "", "//"));
+  EXPECT_EQ("/path/to/src/foo/", RebaseOne(scope, "foo/", "", "//"));
+  EXPECT_EQ("/path/to/src/tools/gn/foo", RebaseOne(scope, "foo", "", "."));
+  EXPECT_EQ("/path/to/other/tools",
+            RebaseOne(scope, "//../other/tools", "", "//"));
+  EXPECT_EQ("/path/to/src/foo/bar",
+            RebaseOne(scope, "//../src/foo/bar", "", "//"));
+  EXPECT_EQ("/path/to", RebaseOne(scope, "//..", "", "//"));
+  EXPECT_EQ("/path", RebaseOne(scope, "../../../..", "", "."));
+  EXPECT_EQ("/path/to/external/dir/",
+            RebaseOne(scope, "//../external/dir/", "", "//"));
 #endif
 }
 
diff --git a/tools/gn/source_dir.cc b/tools/gn/source_dir.cc
index 0966cc6..d9fb4cc 100644
--- a/tools/gn/source_dir.cc
+++ b/tools/gn/source_dir.cc
@@ -71,7 +71,7 @@
   if (str.size() >= 2 && str[0] == '/' && str[1] == '/') {
     // Source-relative.
     ret.value_.assign(str.data(), str.size());
-    NormalizePath(&ret.value_);
+    NormalizePath(&ret.value_, source_root);
     return ret;
   } else if (IsPathAbsolute(str)) {
     if (source_root.empty() ||
@@ -145,7 +145,7 @@
     ret.value_.assign(str.data(), str.size());
     if (!EndsWithSlash(ret.value_))
       ret.value_.push_back('/');
-    NormalizePath(&ret.value_);
+    NormalizePath(&ret.value_, source_root);
     return ret;
   } else if (IsPathAbsolute(str)) {
     if (source_root.empty() ||
diff --git a/tools/gn/source_dir_unittest.cc b/tools/gn/source_dir_unittest.cc
index 04684e6..0c73865e 100644
--- a/tools/gn/source_dir_unittest.cc
+++ b/tools/gn/source_dir_unittest.cc
@@ -61,11 +61,41 @@
           Value(nullptr, "../../foo"), &err, source_root) ==
       SourceFile("/C:/source/foo"));
   EXPECT_FALSE(err.has_error());
+
+  EXPECT_TRUE(base.ResolveRelativeFile(
+          Value(nullptr, "//../foo"), &err, source_root) ==
+      SourceFile("/C:/source/foo"));
+  EXPECT_FALSE(err.has_error());
+
+  EXPECT_TRUE(base.ResolveRelativeFile(
+          Value(nullptr, "//../root/foo"), &err, source_root) ==
+      SourceFile("/C:/source/root/foo"));
+  EXPECT_FALSE(err.has_error());
+
+  EXPECT_TRUE(base.ResolveRelativeFile(
+          Value(nullptr, "//../../../foo/bar"), &err, source_root) ==
+      SourceFile("/foo/bar"));
+  EXPECT_FALSE(err.has_error());
 #else
   EXPECT_TRUE(base.ResolveRelativeFile(
           Value(nullptr, "../../foo"), &err, source_root) ==
       SourceFile("/source/foo"));
   EXPECT_FALSE(err.has_error());
+
+  EXPECT_TRUE(base.ResolveRelativeFile(
+          Value(nullptr, "//../foo"), &err, source_root) ==
+      SourceFile("/source/foo"));
+  EXPECT_FALSE(err.has_error());
+
+  EXPECT_TRUE(base.ResolveRelativeFile(
+          Value(nullptr, "//../root/foo"), &err, source_root) ==
+      SourceFile("/source/root/foo"));
+  EXPECT_FALSE(err.has_error());
+
+  EXPECT_TRUE(base.ResolveRelativeFile(
+          Value(nullptr, "//../../../foo/bar"), &err, source_root) ==
+      SourceFile("/foo/bar"));
+  EXPECT_FALSE(err.has_error());
 #endif
 
 #if defined(OS_WIN)
@@ -120,11 +150,27 @@
           Value(nullptr, "../../foo"), &err, source_root) ==
       SourceDir("/C:/source/foo/"));
   EXPECT_FALSE(err.has_error());
+  EXPECT_TRUE(base.ResolveRelativeDir(
+          Value(nullptr, "//../foo"), &err, source_root) ==
+      SourceDir("/C:/source/foo/"));
+  EXPECT_FALSE(err.has_error());
+  EXPECT_TRUE(base.ResolveRelativeDir(
+          Value(nullptr, "//.."), &err, source_root) ==
+      SourceDir("/C:/source/"));
+  EXPECT_FALSE(err.has_error());
 #else
   EXPECT_TRUE(base.ResolveRelativeDir(
           Value(nullptr, "../../foo"), &err, source_root) ==
       SourceDir("/source/foo/"));
   EXPECT_FALSE(err.has_error());
+  EXPECT_TRUE(base.ResolveRelativeDir(
+          Value(nullptr, "//../foo"), &err, source_root) ==
+      SourceDir("/source/foo/"));
+  EXPECT_FALSE(err.has_error());
+  EXPECT_TRUE(base.ResolveRelativeDir(
+          Value(nullptr, "//.."), &err, source_root) ==
+      SourceDir("/source/"));
+  EXPECT_FALSE(err.has_error());
 #endif
 
 #if defined(OS_WIN)
diff --git a/tools/gn/trace.cc b/tools/gn/trace.cc
index 4746310..5844293 100644
--- a/tools/gn/trace.cc
+++ b/tools/gn/trace.cc
@@ -9,6 +9,8 @@
 #include <sstream>
 #include <vector>
 
+#include "base/command_line.h"
+#include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/json/string_escape.h"
 #include "base/logging.h"
diff --git a/tools/gn/trace.h b/tools/gn/trace.h
index e32f319e..de8ab09d 100644
--- a/tools/gn/trace.h
+++ b/tools/gn/trace.h
@@ -7,14 +7,17 @@
 
 #include <string>
 
-#include "base/command_line.h"
-#include "base/files/file_path.h"
 #include "base/macros.h"
 #include "base/threading/platform_thread.h"
 #include "base/time/time.h"
 
 class Label;
 
+namespace base {
+class CommandLine;
+class FilePath;
+}
+
 class TraceItem {
  public:
   enum Type {
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml
index 536e640..e074c27 100644
--- a/tools/metrics/actions/actions.xml
+++ b/tools/metrics/actions/actions.xml
@@ -7936,21 +7936,25 @@
 <action name="MobileFirstEditInOmnibox">
   <owner>Please list the metric's owners. Add more owner tags as needed.</owner>
   <description>Please enter the description of this user action.</description>
+  <obsolete>Deprecated as of 12/2015</obsolete>
 </action>
 
 <action name="MobileFocusedFakeboxOnNtp">
   <owner>Please list the metric's owners. Add more owner tags as needed.</owner>
   <description>Please enter the description of this user action.</description>
+  <obsolete>Deprecated as of 12/2015</obsolete>
 </action>
 
 <action name="MobileFocusedOmniboxNotOnNtp">
   <owner>Please list the metric's owners. Add more owner tags as needed.</owner>
   <description>Please enter the description of this user action.</description>
+  <obsolete>Deprecated as of 12/2015</obsolete>
 </action>
 
 <action name="MobileFocusedOmniboxOnNtp">
   <owner>Please list the metric's owners. Add more owner tags as needed.</owner>
   <description>Please enter the description of this user action.</description>
+  <obsolete>Deprecated as of 12/2015</obsolete>
 </action>
 
 <action name="MobileFre.SignInShown">
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 7ad19572..abd8810 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -367,6 +367,16 @@
   </summary>
 </histogram>
 
+<histogram name="AppBanners.MinutesFromFirstVisitToBannerShown" units="minutes">
+  <owner>dominickn@chromium.org</owner>
+  <summary>
+    App banners promote an application related to the current website, and are
+    requested specifically through the current page's HTML.  This stat tracks
+    the number of minutes between the first recorded visit to an origin and the
+    time when the banner is actually shown.
+  </summary>
+</histogram>
+
 <histogram name="AppBanners.UserResponse" enum="AppBannersUserResponse">
   <owner>dominickn@chromium.org</owner>
   <summary>
@@ -10756,6 +10766,23 @@
   </summary>
 </histogram>
 
+<histogram name="Event.PassiveListeners" enum="EventResultType">
+  <owner>dtapuska@chromium.org</owner>
+  <summary>
+    The result of handling of MouseWheel, TouchStart, TouchMove, TouchEnd events
+    in the renderer.
+  </summary>
+</histogram>
+
+<histogram name="Event.PassiveListeners.Latency" units="microseconds">
+  <owner>dtapuska@chromium.org</owner>
+  <summary>
+    Time between when a cancelable event was generated and the event processed
+    yet no action was executed for the event. This histogram tracks the
+    potential benefit of using passive events listeners.
+  </summary>
+</histogram>
+
 <histogram name="Event.SingleTapType" enum="TapDelayType">
   <owner>rbyers@chromium.org</owner>
   <summary>
@@ -20354,6 +20381,16 @@
   </summary>
 </histogram>
 
+<histogram name="MobileStartup.TimeSinceLastUse" units="minutes">
+  <owner>knn@chromium.org</owner>
+  <summary>
+    Android: The time since last use until Chrome is launched from the home
+    screen. This is measured from the time the last tab is closed until a Main
+    intent is received. Has a minute level precision for first 10 minutes
+    increasing exponentially till 30 days.
+  </summary>
+</histogram>
+
 <histogram name="MobileStartup.ToolbarFirstDrawTime" units="milliseconds">
   <owner>yusufo@chromium.org</owner>
   <summary>
@@ -50551,6 +50588,33 @@
   </summary>
 </histogram>
 
+<histogram name="UpdateEngine.CertificateCheck.Download"
+    enum="UpdateEngineCertificateCheckStatus">
+  <owner>deymo@chromium.org</owner>
+  <summary>
+    The status of the certificate check done when downloading a payload over
+    HTTPS. Note that most downloads are done over HTTP.
+
+    This is reported on every HTTPS connection to the payload download server.
+    Connection drops on the same payload may report different values.
+
+    This metric is specific to ChromeOS.
+  </summary>
+</histogram>
+
+<histogram name="UpdateEngine.CertificateCheck.UpdateCheck"
+    enum="UpdateEngineCertificateCheckStatus">
+  <owner>deymo@chromium.org</owner>
+  <summary>
+    The status of the certificate check done when querying Omaha for a new
+    version.
+
+    This is reported on every update check.
+
+    This metric is specific to ChromeOS.
+  </summary>
+</histogram>
+
 <histogram name="UpdateEngine.Check.DownloadErrorCode"
     enum="UpdateEngineDownloadErrorCode">
   <owner>zeuthen@chromium.org</owner>
@@ -51218,6 +51282,12 @@
   <summary>Time spent doing a full GC during an IdleNotification.</summary>
 </histogram>
 
+<histogram name="V8.GCFinalizeMC" units="milliseconds">
+  <owner>ulan@chromium.org</owner>
+  <owner>hpayer@chromium.org</owner>
+  <summary>Time spent in finalize incremental mark-sweep phase of GC.</summary>
+</histogram>
+
 <histogram name="V8.GCFinalizeMCReduceMemory" units="milliseconds">
   <owner>ulan@chromium.org</owner>
   <owner>hpayer@chromium.org</owner>
@@ -51227,6 +51297,10 @@
 </histogram>
 
 <histogram name="V8.GCFinalzeMC" units="milliseconds">
+  <obsolete>
+    This histogram has been replaced by V8.GCFinalizeMC because of typo in the
+    name.
+  </obsolete>
   <owner>ulan@chromium.org</owner>
   <owner>hpayer@chromium.org</owner>
   <summary>Time spent in finalize incremental mark-sweep phase of GC.</summary>
@@ -55989,6 +56063,8 @@
   <int value="98" label="BDH_CHARACTERISTIC_ALREADY_SUBSCRIBED"/>
   <int value="99" label="RFH_OWNER_PROPERTY"/>
   <int value="100" label="BDH_EMPTY_OR_INVALID_FILTERS"/>
+  <int value="101" label="WC_CONTENT_WITH_CERT_ERRORS_BAD_SECURITY_INFO"/>
+  <int value="102" label="RFMF_RENDERER_FAKED_ITS_OWN_DEATH"/>
 </enum>
 
 <enum name="BadMessageReasonExtensions" type="int">
@@ -57854,6 +57930,7 @@
   <int value="7010" label="SBOX_FATAL_CLOSEHANDLES"/>
   <int value="7011" label="SBOX_FATAL_MITIGATION"/>
   <int value="7012" label="SBOX_FATAL_MEMORY_EXCEEDED"/>
+  <int value="7013" label="SBOX_FATAL_WARMUP"/>
   <int value="529697949" label="CPP_EH_EXCEPTION"/>
   <int value="533692099" label="STATUS_GUARD_PAGE_VIOLATION"/>
   <int value="1073740791" label="STATUS_STACK_BUFFER_OVERRUN"/>
@@ -60411,6 +60488,13 @@
   <int value="128" label="Request type matched."/>
 </enum>
 
+<enum name="EventResultType" type="int">
+  <int value="0" label="Passive"/>
+  <int value="1" label="Uncancelable"/>
+  <int value="2" label="Cancelable and not canceled"/>
+  <int value="3" label="Cancelable and canceled"/>
+</enum>
+
 <enum name="EVWhitelistStatus" type="int">
   <int value="0" label="Not present"/>
   <int value="1" label="Invalid"/>
@@ -63672,6 +63756,32 @@
   <int value="1038" label="PresentationConnectionClose"/>
   <int value="1039" label="SVG1DOMShape"/>
   <int value="1040" label="SVG1DOMText"/>
+  <int value="1041" label="RTCPeerConnectionConstructorConstraints"/>
+  <int value="1042" label="RTCPeerConnectionConstructorCompliant"/>
+  <int value="1043"
+      label="RTCPeerConnectionCreateOfferLegacyNoFailureCallback"/>
+  <int value="1044" label="RTCPeerConnectionCreateOfferLegacyFailureCallback"/>
+  <int value="1045" label="RTCPeerConnectionCreateOfferLegacyConstraints"/>
+  <int value="1046" label="RTCPeerConnectionCreateOfferLegacyOfferOptions"/>
+  <int value="1047" label="RTCPeerConnectionCreateOfferLegacyCompliant"/>
+  <int value="1048"
+      label="RTCPeerConnectionCreateAnswerLegacyNoFailureCallback"/>
+  <int value="1049" label="RTCPeerConnectionCreateAnswerLegacyFailureCallback"/>
+  <int value="1050" label="RTCPeerConnectionCreateAnswerLegacyConstraints"/>
+  <int value="1051" label="RTCPeerConnectionCreateAnswerLegacyCompliant"/>
+  <int value="1052"
+      label="RTCPeerConnectionSetLocalDescriptionLegacyNoSuccessCallback"/>
+  <int value="1053"
+      label="RTCPeerConnectionSetLocalDescriptionLegacyNoFailureCallback"/>
+  <int value="1054"
+      label="RTCPeerConnectionSetLocalDescriptionLegacyCompliant"/>
+  <int value="1055"
+      label="RTCPeerConnectionSetRemoteDescriptionLegacyNoSuccessCallback"/>
+  <int value="1056"
+      label="RTCPeerConnectionSetRemoteDescriptionLegacyNoFailureCallback"/>
+  <int value="1057"
+      label="RTCPeerConnectionSetRemoteDescriptionLegacyCompliant"/>
+  <int value="1058" label="RTCPeerConnectionGetStatsLegacyNonCompliant"/>
 </enum>
 
 <enum name="FetchRequestMode" type="int">
@@ -66575,6 +66685,13 @@
   <int value="12" label="ERROR_SOURCE_NOT_FOUND">
     Broker didn't have a channel of communication with the source process.
   </int>
+  <int value="13" label="ERROR_COULD_NOT_OPEN_SOURCE_OR_DEST">
+    Broker could not open the source or destination process with extra
+    privileges.
+  </int>
+  <int value="14" label="ERROR_INVALID_PERMISSIONS">
+    Broker was asked to transfer a HANDLE with invalid permissions.
+  </int>
 </enum>
 
 <enum name="IPCAttachmentBrokerUnprivilegedBrokerAttachmentError" type="int">
@@ -67579,6 +67696,7 @@
   <int value="-2008272679" label="disable-webrtc-hw-encoding"/>
   <int value="-2003354337"
       label="enable-search-button-in-omnibox-for-str-or-iip"/>
+  <int value="-1999892428" label="force-ui-direction"/>
   <int value="-1998927516" label="enable-md-settings"/>
   <int value="-1985025593" label="file-manager-enable-new-gallery"/>
   <int value="-1980328793" label="trace-upload-url"/>
@@ -77631,6 +77749,20 @@
   <int value="10" label="Abnormal Termination"/>
 </enum>
 
+<enum name="UpdateEngineCertificateCheckStatus" type="int">
+  <int value="0" label="Valid certificate">
+    The certificate is valid and the same as seen before or the first time we
+    see a certificate.
+  </int>
+  <int value="1" label="Changed certificate">
+    The certificate is valid, but is different than a previously seen
+    certificate for the selected server.
+  </int>
+  <int value="2" label="Certificate check failed">
+    The certificate validation failed.
+  </int>
+</enum>
+
 <enum name="UpdateEngineCheckReaction" type="int">
   <int value="0" label="Updating"/>
   <int value="1" label="Ignoring"/>
diff --git a/tools/perf/benchmarks/smoothness.py b/tools/perf/benchmarks/smoothness.py
index 769b679..be9c195 100644
--- a/tools/perf/benchmarks/smoothness.py
+++ b/tools/perf/benchmarks/smoothness.py
@@ -2,6 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+
 from core import perf_benchmark
 
 from benchmarks import silk_flags
diff --git a/tools/telemetry/bin/android/arm64-v8a/run_pie.sha1 b/tools/telemetry/bin/android/arm64-v8a/run_pie.sha1
deleted file mode 100644
index c22a415..0000000
--- a/tools/telemetry/bin/android/arm64-v8a/run_pie.sha1
+++ /dev/null
@@ -1 +0,0 @@
-30cdda413b6cdaf4646c0522f6032aa17a3ddeb6
\ No newline at end of file
diff --git a/tools/telemetry/bin/android/armeabi-v7a/run_pie.sha1 b/tools/telemetry/bin/android/armeabi-v7a/run_pie.sha1
deleted file mode 100644
index 1811d995..0000000
--- a/tools/telemetry/bin/android/armeabi-v7a/run_pie.sha1
+++ /dev/null
@@ -1 +0,0 @@
-464e2b4b72281b18ef1c312aa8d125e750c6c8b4
\ No newline at end of file
diff --git a/tools/telemetry/catapult_base/cloud_storage.py b/tools/telemetry/catapult_base/cloud_storage.py
index f4dca2a..ae8223e2 100644
--- a/tools/telemetry/catapult_base/cloud_storage.py
+++ b/tools/telemetry/catapult_base/cloud_storage.py
@@ -43,7 +43,7 @@
 BUCKET_ALIAS_NAMES = BUCKET_ALIASES.keys()
 
 
-_GSUTIL_PATH = os.path.join(path.GetTelemetryDir(), 'third_party', 'gsutilz',
+_GSUTIL_PATH = os.path.join(util.GetCatapultDir(), 'third_party', 'gsutil',
                             'gsutil')
 
 # TODO(tbarzic): A workaround for http://crbug.com/386416 and
diff --git a/tools/telemetry/catapult_base/dependency_manager/cloud_storage_info.py b/tools/telemetry/catapult_base/dependency_manager/cloud_storage_info.py
index 880cfe2..1e1c1d5 100644
--- a/tools/telemetry/catapult_base/dependency_manager/cloud_storage_info.py
+++ b/tools/telemetry/catapult_base/dependency_manager/cloud_storage_info.py
@@ -2,6 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import errno
 import logging
 import os
 import stat
@@ -63,7 +64,13 @@
 
     download_dir = os.path.dirname(self._download_path)
     if not os.path.exists(download_dir):
-      os.makedirs(download_dir)
+      try:
+        os.makedirs(download_dir)
+      except OSError as e:
+        # The logic above is racy, and os.makedirs will raise an OSError if
+        # the directory exists.
+        if e.errno != errno.EEXIST:
+          raise
 
     dependency_path = self._download_path
     cloud_storage.GetIfHashChanged(
diff --git a/tools/telemetry/telemetry/android/shared_android_state.py b/tools/telemetry/telemetry/android/shared_android_state.py
index f2ac14f5..bb813bd 100644
--- a/tools/telemetry/telemetry/android/shared_android_state.py
+++ b/tools/telemetry/telemetry/android/shared_android_state.py
@@ -33,8 +33,10 @@
     self._finder_options = finder_options
     self._android_app = None
     self._current_story = None
+    device = android_device.GetDevice(finder_options)
+    assert device, 'Android device required.'
     self._android_platform = platform.GetPlatformForDevice(
-        android_device.GetDevice(finder_options), finder_options)
+        device, finder_options)
     assert self._android_platform, 'Unable to create android platform.'
     assert isinstance(
         self._android_platform, android_platform.AndroidPlatform)
diff --git a/tools/telemetry/telemetry/core/util.py b/tools/telemetry/telemetry/core/util.py
index 8d8f705c..26bdd486 100644
--- a/tools/telemetry/telemetry/core/util.py
+++ b/tools/telemetry/telemetry/core/util.py
@@ -23,12 +23,11 @@
 
 def GetTelemetryDir():
   return os.path.normpath(os.path.join(
-      __file__, '..', '..', '..'))
+      os.path.abspath(__file__), '..', '..', '..'))
 
 
 def GetTelemetryThirdPartyDir():
-  return os.path.normpath(os.path.join(
-      __file__, '..', '..', '..', 'third_party'))
+  return os.path.join(GetTelemetryDir(), 'third_party')
 
 
 def GetUnittestDataDir():
@@ -40,6 +39,12 @@
   return os.path.normpath(os.path.join(GetTelemetryDir(), '..', '..'))
 
 
+# TODO(aiolos): Move this over to the path in catapult after the migration.
+def GetCatapultDir():
+  return os.path.normpath(os.path.join(
+      GetTelemetryDir(), '..', '..', 'third_party', 'catapult'))
+
+
 _counter = [0]
 def _GetUniqueModuleName():
   _counter[0] += 1
diff --git a/tools/telemetry/telemetry/internal/actions/repeatable_scroll.py b/tools/telemetry/telemetry/internal/actions/repeatable_scroll.py
index ef33399..79ba4c4 100644
--- a/tools/telemetry/telemetry/internal/actions/repeatable_scroll.py
+++ b/tools/telemetry/telemetry/internal/actions/repeatable_scroll.py
@@ -9,13 +9,14 @@
 class RepeatableScrollAction(page_action.PageAction):
 
   def __init__(self, x_scroll_distance_ratio=0.0, y_scroll_distance_ratio=0.5,
-               repeat_count=0, repeat_delay_ms=250):
+               repeat_count=0, repeat_delay_ms=250, timeout=60):
     super(RepeatableScrollAction, self).__init__()
     self._x_scroll_distance_ratio = x_scroll_distance_ratio
     self._y_scroll_distance_ratio = y_scroll_distance_ratio
     self._repeat_count = repeat_count
     self._repeat_delay_ms = repeat_delay_ms
     self._windowsize = []
+    self._timeout = timeout
 
   def WillRunAction(self, tab):
     # Get the dimensions of the screen.
@@ -35,4 +36,5 @@
         repeatCount=self._repeat_count,
         repeatDelayMs=self._repeat_delay_ms,
         interactionMarkerName=timeline_interaction_record.GetJavaScriptMarker(
-            'Gesture_ScrollAction', [timeline_interaction_record.REPEATABLE]))
+            'Gesture_ScrollAction', [timeline_interaction_record.REPEATABLE]),
+        timeout=self._timeout)
diff --git a/tools/telemetry/telemetry/internal/browser/web_contents.py b/tools/telemetry/telemetry/internal/browser/web_contents.py
index 25f19806..d360f1d8 100644
--- a/tools/telemetry/telemetry/internal/browser/web_contents.py
+++ b/tools/telemetry/telemetry/internal/browser/web_contents.py
@@ -300,7 +300,8 @@
                               xOverscroll=None, yOverscroll=None,
                               preventFling=True, speed=None,
                               gestureSourceType=None, repeatCount=None,
-                              repeatDelayMs=None, interactionMarkerName=None):
+                              repeatDelayMs=None, interactionMarkerName=None,
+                              timeout=60):
     """Runs an inspector command that causes a repeatable browser driven scroll.
 
     Args:
@@ -327,4 +328,5 @@
         preventFling=preventFling, speed=speed,
         gestureSourceType=gestureSourceType, repeatCount=repeatCount,
         repeatDelayMs=repeatDelayMs,
-        interactionMarkerName=interactionMarkerName)
+        interactionMarkerName=interactionMarkerName,
+        timeout=timeout)
diff --git a/tools/telemetry/telemetry/internal/platform/android_device.py b/tools/telemetry/telemetry/internal/platform/android_device.py
index 20608639..9b62989 100644
--- a/tools/telemetry/telemetry/internal/platform/android_device.py
+++ b/tools/telemetry/telemetry/internal/platform/android_device.py
@@ -103,21 +103,21 @@
         'No adb command found. Will not try searching for Android browsers.')
     return None
 
-  if (finder_options.device
-      and finder_options.device in GetDeviceSerials(finder_options)):
-    return AndroidDevice(
-        finder_options.device,
-        enable_performance_mode=not finder_options.no_performance_mode)
-
   if finder_options.android_blacklist_file:
     blacklist = device_blacklist.Blacklist(
         finder_options.android_blacklist_file)
   else:
     blacklist = None
 
+  if (finder_options.device
+      and finder_options.device in GetDeviceSerials(blacklist)):
+    return AndroidDevice(
+        finder_options.device,
+        enable_performance_mode=not finder_options.no_performance_mode)
+
   devices = AndroidDevice.GetAllConnectedDevices(blacklist)
   if len(devices) == 0:
-    logging.info('No android devices found.')
+    logging.warn('No android devices found.')
     return None
   if len(devices) > 1:
     logging.warn(
@@ -129,6 +129,9 @@
 
 def CanDiscoverDevices():
   """Returns true if devices are discoverable via adb."""
+  if os.name != 'posix':
+    return False
+
   adb_path = constants.GetAdbPath()
   if os.path.isabs(adb_path) and not os.path.exists(adb_path):
     return False
diff --git a/tools/telemetry/telemetry/internal/platform/android_device_unittest.py b/tools/telemetry/telemetry/internal/platform/android_device_unittest.py
index f953b30..85eaadb 100644
--- a/tools/telemetry/telemetry/internal/platform/android_device_unittest.py
+++ b/tools/telemetry/telemetry/internal/platform/android_device_unittest.py
@@ -4,19 +4,27 @@
 
 import unittest
 
+from telemetry import decorators
 from telemetry.internal.browser import browser_options
 from telemetry.internal.platform import android_device
 from telemetry.testing import system_stub
 import mock
 
 from devil.android import device_utils
+from devil.android import device_blacklist
 
 
 class _BaseAndroidDeviceTest(unittest.TestCase):
   def setUp(self):
+    def check_blacklist_arg(blacklist):
+      self.assertTrue(blacklist is None
+                      or isinstance(blacklist, device_blacklist.Blacklist))
+      return mock.DEFAULT
+
     self._healthy_device_patcher = mock.patch(
         'devil.android.device_utils.DeviceUtils.HealthyDevices')
     self._healthy_device_mock = self._healthy_device_patcher.start()
+    self._healthy_device_mock.side_effect = check_blacklist_arg
     self._android_device_stub = system_stub.Override(
         android_device, ['subprocess', 'logging'])
 
@@ -31,6 +39,7 @@
 
 
 class AndroidDeviceTest(_BaseAndroidDeviceTest):
+  @decorators.Enabled('android')
   def testGetAllAttachedAndroidDevices(self):
     self._healthy_device_mock.return_value = [
         self._GetMockDeviceUtils('01'),
@@ -42,6 +51,7 @@
         set(device.device_id for device in
             android_device.AndroidDevice.GetAllConnectedDevices(None)))
 
+  @decorators.Enabled('android')
   def testNoAdbReturnsNone(self):
     finder_options = browser_options.BrowserFinderOptions()
     with (
@@ -50,6 +60,7 @@
       self.assertEquals([], self._android_device_stub.logging.warnings)
       self.assertIsNone(android_device.GetDevice(finder_options))
 
+  @decorators.Enabled('android')
   def testAdbNoDevicesReturnsNone(self):
     finder_options = browser_options.BrowserFinderOptions()
     with mock.patch('os.path.isabs', return_value=False):
@@ -57,6 +68,7 @@
       self.assertEquals([], self._android_device_stub.logging.warnings)
       self.assertIsNone(android_device.GetDevice(finder_options))
 
+  @decorators.Enabled('android')
   def testAdbTwoDevicesReturnsNone(self):
     finder_options = browser_options.BrowserFinderOptions()
     with mock.patch('os.path.isabs', return_value=False):
@@ -71,6 +83,7 @@
           self._android_device_stub.logging.warnings)
       self.assertIsNone(device)
 
+  @decorators.Enabled('android')
   def testAdbPickOneDeviceReturnsDeviceInstance(self):
     finder_options = browser_options.BrowserFinderOptions()
     finder_options.device = '555d14fecddddddd'  # pick one
@@ -82,6 +95,7 @@
       self.assertEquals([], self._android_device_stub.logging.warnings)
       self.assertEquals('555d14fecddddddd', device.device_id)
 
+  @decorators.Enabled('android')
   def testAdbOneDeviceReturnsDeviceInstance(self):
     finder_options = browser_options.BrowserFinderOptions()
     with mock.patch('os.path.isabs', return_value=False):
@@ -93,6 +107,7 @@
 
 
 class FindAllAvailableDevicesTest(_BaseAndroidDeviceTest):
+  @decorators.Enabled('android')
   def testAdbNoDeviceReturnsEmptyList(self):
     finder_options = browser_options.BrowserFinderOptions()
     with mock.patch('os.path.isabs', return_value=False):
@@ -102,6 +117,7 @@
       self.assertIsNotNone(devices)
       self.assertEquals(len(devices), 0)
 
+  @decorators.Enabled('android')
   def testAdbOneDeviceReturnsListWithOneDeviceInstance(self):
     finder_options = browser_options.BrowserFinderOptions()
     with mock.patch('os.path.isabs', return_value=False):
@@ -113,6 +129,7 @@
       self.assertEquals(len(devices), 1)
       self.assertEquals('015d14fec128220c', devices[0].device_id)
 
+  @decorators.Enabled('android')
   def testAdbMultipleDevicesReturnsListWithAllDeviceInstances(self):
     finder_options = browser_options.BrowserFinderOptions()
     with mock.patch('os.path.isabs', return_value=False):
diff --git a/tools/telemetry/telemetry/internal/platform/android_platform_backend.py b/tools/telemetry/telemetry/internal/platform/android_platform_backend.py
index 5c8f333..2d97821 100644
--- a/tools/telemetry/telemetry/internal/platform/android_platform_backend.py
+++ b/tools/telemetry/telemetry/internal/platform/android_platform_backend.py
@@ -71,7 +71,6 @@
     'memtrack_helper',
     'md5sum_dist/md5sum_bin',
     'purge_ashmem',
-    'run_pie',
   ]
 
   host_tools = [
diff --git a/tools/telemetry/telemetry/internal/util/binary_manager.py b/tools/telemetry/telemetry/internal/util/binary_manager.py
index e277b70..fb89615 100644
--- a/tools/telemetry/telemetry/internal/util/binary_manager.py
+++ b/tools/telemetry/telemetry/internal/util/binary_manager.py
@@ -10,6 +10,7 @@
 from catapult_base import dependency_manager
 from telemetry.core import exceptions
 from telemetry.core import util
+from devil import devil_env
 
 
 TELEMETRY_PROJECT_CONFIG = os.path.join(
@@ -34,6 +35,8 @@
     configs.insert(0, dependency_manager.BaseConfig(environment_config))
   _dependency_manager = dependency_manager.DependencyManager(configs)
 
+  devil_env.config.Initialize()
+
 
 def FetchPath(binary_name, arch, platform):
   """ Return a path to the appropriate executable for <binary_name>, downloading
diff --git a/tools/telemetry/telemetry/internal/util/path.py b/tools/telemetry/telemetry/internal/util/path.py
index 5946a92..45c3ecb8 100644
--- a/tools/telemetry/telemetry/internal/util/path.py
+++ b/tools/telemetry/telemetry/internal/util/path.py
@@ -7,7 +7,7 @@
 from telemetry.core import util
 
 
-# TODO(dtu): Move these functions from core.util to here.
+# TODO(aiolos): Move these functions to catapult_base or here.
 GetBaseDir = util.GetBaseDir
 GetTelemetryDir = util.GetTelemetryDir
 GetUnittestDataDir = util.GetUnittestDataDir
diff --git a/tools/telemetry/telemetry/page/action_runner.py b/tools/telemetry/telemetry/page/action_runner.py
index 805e62d6..d36a6c1 100644
--- a/tools/telemetry/telemetry/page/action_runner.py
+++ b/tools/telemetry/telemetry/page/action_runner.py
@@ -362,7 +362,8 @@
   def RepeatableBrowserDrivenScroll(self, x_scroll_distance_ratio=0.0,
                                     y_scroll_distance_ratio=0.5,
                                     repeat_count=0,
-                                    repeat_delay_ms=250):
+                                    repeat_delay_ms=250,
+                                    timeout=60):
     """Perform a browser driven repeatable scroll gesture.
 
     The scroll gesture is driven from the browser, this is useful because the
@@ -381,7 +382,7 @@
         x_scroll_distance_ratio=x_scroll_distance_ratio,
         y_scroll_distance_ratio=y_scroll_distance_ratio,
         repeat_count=repeat_count,
-        repeat_delay_ms=repeat_delay_ms))
+        repeat_delay_ms=repeat_delay_ms, timeout=timeout))
 
   def ScrollElement(self, selector=None, text=None, element_function=None,
                     left_start_ratio=0.5, top_start_ratio=0.5,
diff --git a/ui/base/clipboard/clipboard.h b/ui/base/clipboard/clipboard.h
index af8f439c..8a5e5dc 100644
--- a/ui/base/clipboard/clipboard.h
+++ b/ui/base/clipboard/clipboard.h
@@ -5,6 +5,8 @@
 #ifndef UI_BASE_CLIPBOARD_CLIPBOARD_H_
 #define UI_BASE_CLIPBOARD_CLIPBOARD_H_
 
+#include <stdint.h>
+
 #include <map>
 #include <string>
 #include <vector>
@@ -148,7 +150,7 @@
   // Returns a sequence number which uniquely identifies clipboard state.
   // This can be used to version the data on the clipboard and determine
   // whether it has changed.
-  virtual uint64 GetSequenceNumber(ClipboardType type) const = 0;
+  virtual uint64_t GetSequenceNumber(ClipboardType type) const = 0;
 
   // Tests whether the clipboard contains a certain format
   virtual bool IsFormatAvailable(const FormatType& format,
diff --git a/ui/base/clipboard/clipboard_aura.cc b/ui/base/clipboard/clipboard_aura.cc
index e6823924..cfe4986 100644
--- a/ui/base/clipboard/clipboard_aura.cc
+++ b/ui/base/clipboard/clipboard_aura.cc
@@ -4,9 +4,11 @@
 
 #include "ui/base/clipboard/clipboard_aura.h"
 
+#include <stdint.h>
+
+#include <limits>
 #include <list>
 
-#include "base/basictypes.h"
 #include "base/files/file_path.h"
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
@@ -210,8 +212,8 @@
   // Reads HTML from the data at the top of clipboard stack.
   void ReadHTML(base::string16* markup,
                 std::string* src_url,
-                uint32* fragment_start,
-                uint32* fragment_end) const {
+                uint32_t* fragment_start,
+                uint32_t* fragment_end) const {
     markup->clear();
     if (src_url)
       src_url->clear();
@@ -226,8 +228,8 @@
     *src_url = data->url();
 
     *fragment_start = 0;
-    DCHECK_LE(markup->length(), kuint32max);
-    *fragment_end = static_cast<uint32>(markup->length());
+    DCHECK_LE(markup->length(), std::numeric_limits<uint32_t>::max());
+    *fragment_end = static_cast<uint32_t>(markup->length());
   }
 
   // Reads RTF from the data at the top of clipboard stack.
@@ -528,7 +530,7 @@
   DeleteClipboard();
 }
 
-uint64 ClipboardAura::GetSequenceNumber(ClipboardType type) const {
+uint64_t ClipboardAura::GetSequenceNumber(ClipboardType type) const {
   DCHECK(CalledOnValidThread());
   return GetClipboard()->sequence_number();
 }
@@ -605,8 +607,8 @@
 void ClipboardAura::ReadHTML(ClipboardType type,
                              base::string16* markup,
                              std::string* src_url,
-                             uint32* fragment_start,
-                             uint32* fragment_end) const {
+                             uint32_t* fragment_start,
+                             uint32_t* fragment_end) const {
   DCHECK(CalledOnValidThread());
   GetClipboard()->ReadHTML(markup, src_url, fragment_start, fragment_end);
 }
diff --git a/ui/base/clipboard/clipboard_aura.h b/ui/base/clipboard/clipboard_aura.h
index e5fbc34..39fd07e 100644
--- a/ui/base/clipboard/clipboard_aura.h
+++ b/ui/base/clipboard/clipboard_aura.h
@@ -17,7 +17,7 @@
   ~ClipboardAura() override;
 
   // Clipboard overrides:
-  uint64 GetSequenceNumber(ClipboardType type) const override;
+  uint64_t GetSequenceNumber(ClipboardType type) const override;
   bool IsFormatAvailable(const FormatType& format,
                          ClipboardType type) const override;
   void Clear(ClipboardType type) override;
diff --git a/ui/base/clipboard/clipboard_aurax11.cc b/ui/base/clipboard/clipboard_aurax11.cc
index b9b53f18..d9759b8d 100644
--- a/ui/base/clipboard/clipboard_aurax11.cc
+++ b/ui/base/clipboard/clipboard_aurax11.cc
@@ -4,12 +4,14 @@
 
 #include "ui/base/clipboard/clipboard_aurax11.h"
 
+#include <stdint.h>
 #include <X11/extensions/Xfixes.h>
 #include <X11/Xatom.h>
+
+#include <limits>
 #include <list>
 #include <set>
 
-#include "base/basictypes.h"
 #include "base/files/file_path.h"
 #include "base/logging.h"
 #include "base/memory/ref_counted_memory.h"
@@ -65,10 +67,10 @@
  public:
   static SelectionChangeObserver* GetInstance();
 
-  uint64 clipboard_sequence_number() const {
+  uint64_t clipboard_sequence_number() const {
     return clipboard_sequence_number_;
   }
-  uint64 primary_sequence_number() const { return primary_sequence_number_; }
+  uint64_t primary_sequence_number() const { return primary_sequence_number_; }
 
  private:
   friend struct base::DefaultSingletonTraits<SelectionChangeObserver>;
@@ -82,8 +84,8 @@
 
   int event_base_;
   Atom clipboard_atom_;
-  uint64 clipboard_sequence_number_;
-  uint64 primary_sequence_number_;
+  uint64_t clipboard_sequence_number_;
+  uint64_t primary_sequence_number_;
 
   DISALLOW_COPY_AND_ASSIGN(SelectionChangeObserver);
 };
@@ -670,7 +672,7 @@
   aurax11_details_->StoreCopyPasteDataAndWait();
 }
 
-uint64 ClipboardAuraX11::GetSequenceNumber(ClipboardType type) const {
+uint64_t ClipboardAuraX11::GetSequenceNumber(ClipboardType type) const {
   DCHECK(CalledOnValidThread());
   if (type == CLIPBOARD_TYPE_COPY_PASTE)
     return SelectionChangeObserver::GetInstance()->clipboard_sequence_number();
@@ -753,8 +755,8 @@
 void ClipboardAuraX11::ReadHTML(ClipboardType type,
                                 base::string16* markup,
                                 std::string* src_url,
-                                uint32* fragment_start,
-                                uint32* fragment_end) const {
+                                uint32_t* fragment_start,
+                                uint32_t* fragment_end) const {
   DCHECK(CalledOnValidThread());
   markup->clear();
   if (src_url)
@@ -768,8 +770,8 @@
     *markup = data.GetHtml();
 
     *fragment_start = 0;
-    DCHECK(markup->length() <= kuint32max);
-    *fragment_end = static_cast<uint32>(markup->length());
+    DCHECK(markup->length() <= std::numeric_limits<uint32_t>::max());
+    *fragment_end = static_cast<uint32_t>(markup->length());
   }
 }
 
diff --git a/ui/base/clipboard/clipboard_mac.h b/ui/base/clipboard/clipboard_mac.h
index d6a1d43..f14bd00 100644
--- a/ui/base/clipboard/clipboard_mac.h
+++ b/ui/base/clipboard/clipboard_mac.h
@@ -17,7 +17,7 @@
   ~ClipboardMac() override;
 
   // Clipboard overrides:
-  uint64 GetSequenceNumber(ClipboardType type) const override;
+  uint64_t GetSequenceNumber(ClipboardType type) const override;
   bool IsFormatAvailable(const FormatType& format,
                          ClipboardType type) const override;
   void Clear(ClipboardType type) override;
diff --git a/ui/base/clipboard/clipboard_mac.mm b/ui/base/clipboard/clipboard_mac.mm
index 306502f..05da58b 100644
--- a/ui/base/clipboard/clipboard_mac.mm
+++ b/ui/base/clipboard/clipboard_mac.mm
@@ -5,8 +5,10 @@
 #include "ui/base/clipboard/clipboard_mac.h"
 
 #import <Cocoa/Cocoa.h>
+#include <stdint.h>
 
-#include "base/basictypes.h"
+#include <limits>
+
 #include "base/files/file_path.h"
 #include "base/logging.h"
 #include "base/mac/mac_util.h"
@@ -183,7 +185,7 @@
   DCHECK(CalledOnValidThread());
 }
 
-uint64 ClipboardMac::GetSequenceNumber(ClipboardType type) const {
+uint64_t ClipboardMac::GetSequenceNumber(ClipboardType type) const {
   DCHECK(CalledOnValidThread());
   DCHECK_EQ(type, CLIPBOARD_TYPE_COPY_PASTE);
 
@@ -264,8 +266,8 @@
 void ClipboardMac::ReadHTML(ClipboardType type,
                             base::string16* markup,
                             std::string* src_url,
-                            uint32* fragment_start,
-                            uint32* fragment_end) const {
+                            uint32_t* fragment_start,
+                            uint32_t* fragment_end) const {
   DCHECK(CalledOnValidThread());
   DCHECK_EQ(type, CLIPBOARD_TYPE_COPY_PASTE);
 
@@ -288,8 +290,8 @@
   }
 
   *fragment_start = 0;
-  DCHECK(markup->length() <= kuint32max);
-  *fragment_end = static_cast<uint32>(markup->length());
+  DCHECK(markup->length() <= std::numeric_limits<uint32_t>::max());
+  *fragment_end = static_cast<uint32_t>(markup->length());
 }
 
 void ClipboardMac::ReadRTF(ClipboardType type, std::string* result) const {
diff --git a/ui/base/resource/resource_bundle.cc b/ui/base/resource/resource_bundle.cc
index 6d042715..784f6e86 100644
--- a/ui/base/resource/resource_bundle.cc
+++ b/ui/base/resource/resource_bundle.cc
@@ -39,6 +39,7 @@
 
 #if defined(OS_ANDROID)
 #include "ui/base/resource/resource_bundle_android.h"
+#include "ui/gfx/android/device_display_info.h"
 #endif
 
 #if defined(OS_CHROMEOS)
@@ -608,9 +609,13 @@
   supported_scale_factors.push_back(SCALE_FACTOR_100P);
 #endif
 #if defined(OS_ANDROID)
-  const gfx::Display display =
-      gfx::Screen::GetNativeScreen()->GetPrimaryDisplay();
-  const float display_density = display.device_scale_factor();
+  float display_density;
+  if (gfx::Display::HasForceDeviceScaleFactor()) {
+    display_density = gfx::Display::GetForcedDeviceScaleFactor();
+  } else {
+    gfx::DeviceDisplayInfo device_info;
+    display_density = device_info.GetDIPScale();
+  }
   const ScaleFactor closest = FindClosestScaleFactorUnsafe(display_density);
   if (closest != SCALE_FACTOR_100P)
     supported_scale_factors.push_back(closest);
diff --git a/ui/compositor/clip_recorder.cc b/ui/compositor/clip_recorder.cc
index 0a3bc15..cec5c3d9 100644
--- a/ui/compositor/clip_recorder.cc
+++ b/ui/compositor/clip_recorder.cc
@@ -10,59 +10,68 @@
 #include "ui/compositor/paint_context.h"
 #include "ui/gfx/canvas.h"
 #include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/rect_conversions.h"
 #include "ui/gfx/path.h"
+#include "ui/gfx/skia_util.h"
 
 namespace ui {
 
-ClipRecorder::ClipRecorder(const PaintContext& context,
-                           const gfx::Size& size_in_layer)
-    : context_(context),
-      bounds_in_layer_(context.ToLayerSpaceBounds(size_in_layer)),
-      num_closers_(0) {}
+ClipRecorder::ClipRecorder(const PaintContext& context)
+    : context_(context), num_closers_(0) {}
 
 ClipRecorder::~ClipRecorder() {
-  for (size_t i = num_closers_; i > 0; --i) {
-    switch (closers_[i - 1]) {
+  for (int i = num_closers_ - 1; i >= 0; --i) {
+    const gfx::Rect& bounds_in_layer = bounds_in_layer_[i];
+    switch (closers_[i]) {
       case CLIP_RECT:
         context_.list_->CreateAndAppendItem<cc::EndClipDisplayItem>(
-            bounds_in_layer_);
+            bounds_in_layer);
         break;
       case CLIP_PATH:
         context_.list_->CreateAndAppendItem<cc::EndClipPathDisplayItem>(
-            bounds_in_layer_);
+            bounds_in_layer);
         break;
     }
   }
 }
 
+void ClipRecorder::RecordCloser(const gfx::Rect& bounds_in_layer,
+                                Closer closer) {
+  DCHECK_LT(num_closers_, kMaxOpCount);
+  closers_[num_closers_] = closer;
+  bounds_in_layer_[num_closers_++] = bounds_in_layer;
+}
+
+static gfx::Rect PathToEnclosingRect(const gfx::Path& path) {
+  return gfx::ToEnclosingRect(gfx::SkRectToRectF(path.getBounds()));
+}
+
 void ClipRecorder::ClipRect(const gfx::Rect& clip_rect) {
   gfx::Rect clip_in_layer_space = context_.ToLayerSpaceRect(clip_rect);
   auto* item = context_.list_->CreateAndAppendItem<cc::ClipDisplayItem>(
       clip_in_layer_space);
   item->SetNew(clip_rect, std::vector<SkRRect>());
-  DCHECK_LT(num_closers_, arraysize(closers_));
-  closers_[num_closers_++] = CLIP_RECT;
+  RecordCloser(clip_in_layer_space, CLIP_RECT);
 }
 
 void ClipRecorder::ClipPath(const gfx::Path& clip_path) {
   bool anti_alias = false;
-  // As a further optimization, consider passing a more granular visual rect.
+  gfx::Rect clip_in_layer_space =
+      context_.ToLayerSpaceRect(PathToEnclosingRect(clip_path));
   auto* item = context_.list_->CreateAndAppendItem<cc::ClipPathDisplayItem>(
-      bounds_in_layer_);
+      clip_in_layer_space);
   item->SetNew(clip_path, SkRegion::kIntersect_Op, anti_alias);
-  DCHECK_LT(num_closers_, arraysize(closers_));
-  closers_[num_closers_++] = CLIP_PATH;
+  RecordCloser(clip_in_layer_space, CLIP_PATH);
 }
 
-void ClipRecorder::ClipPathWithAntiAliasing(
-    const gfx::Path& clip_path) {
+void ClipRecorder::ClipPathWithAntiAliasing(const gfx::Path& clip_path) {
   bool anti_alias = true;
-  // As a further optimization, consider passing a more granular visual rect.
+  gfx::Rect clip_in_layer_space =
+      context_.ToLayerSpaceRect(PathToEnclosingRect(clip_path));
   auto* item = context_.list_->CreateAndAppendItem<cc::ClipPathDisplayItem>(
-      bounds_in_layer_);
+      clip_in_layer_space);
   item->SetNew(clip_path, SkRegion::kIntersect_Op, anti_alias);
-  DCHECK_LT(num_closers_, arraysize(closers_));
-  closers_[num_closers_++] = CLIP_PATH;
+  RecordCloser(clip_in_layer_space, CLIP_PATH);
 }
 
 }  // namespace ui
diff --git a/ui/compositor/clip_recorder.h b/ui/compositor/clip_recorder.h
index addd869..e1e4790 100644
--- a/ui/compositor/clip_recorder.h
+++ b/ui/compositor/clip_recorder.h
@@ -24,13 +24,11 @@
 
 // A class to provide scoped clips of painting to a DisplayItemList. The clip
 // provided will be applied to any DisplayItems added to the DisplayItemList
-// while this object is alive. In other words, any nested PaintRecorders or
-// other ClipRecorders will be clipped.
+// while this object is alive. In other words, any nested recorders will be
+// clipped.
 class COMPOSITOR_EXPORT ClipRecorder {
  public:
-  // |size_in_layer| is the size in layer space dimensions surrounding
-  // everything that's visible.
-  ClipRecorder(const PaintContext& context, const gfx::Size& size_in_layer);
+  explicit ClipRecorder(const PaintContext& context);
   ~ClipRecorder();
 
   void ClipRect(const gfx::Rect& clip_rect);
@@ -42,12 +40,16 @@
     CLIP_RECT,
     CLIP_PATH,
   };
+
+  void RecordCloser(const gfx::Rect& bounds_in_layer, Closer);
+
   const PaintContext& context_;
-  const gfx::Rect bounds_in_layer_;
   // If someone needs to do more than this many operations with a single
-  // ClipRecorder then increase the size of the closers_ array.
-  Closer closers_[4];
-  size_t num_closers_;
+  // ClipRecorder then we'll increase this.
+  enum : int { kMaxOpCount = 4 };
+  Closer closers_[kMaxOpCount];
+  gfx::Rect bounds_in_layer_[kMaxOpCount];
+  int num_closers_;
 
   DISALLOW_COPY_AND_ASSIGN(ClipRecorder);
 };
diff --git a/ui/compositor/compositing_recorder.cc b/ui/compositor/compositing_recorder.cc
index fca8ad9..f3d49cff 100644
--- a/ui/compositor/compositing_recorder.cc
+++ b/ui/compositor/compositing_recorder.cc
@@ -12,10 +12,10 @@
 namespace ui {
 
 CompositingRecorder::CompositingRecorder(const PaintContext& context,
-                                         const gfx::Size& size_in_layer,
+                                         const gfx::Size& size_in_context,
                                          uint8_t alpha)
     : context_(context),
-      bounds_in_layer_(context.ToLayerSpaceBounds(size_in_layer)),
+      bounds_in_layer_(context.ToLayerSpaceBounds(size_in_context)),
       saved_(alpha < 255) {
   if (!saved_)
     return;
diff --git a/ui/compositor/compositing_recorder.h b/ui/compositor/compositing_recorder.h
index 499f424b..e50f692 100644
--- a/ui/compositor/compositing_recorder.h
+++ b/ui/compositor/compositing_recorder.h
@@ -25,10 +25,10 @@
 class COMPOSITOR_EXPORT CompositingRecorder {
  public:
   // |alpha| is a value between 0 and 255, where 0 is transparent and 255 is
-  // opaque. |size_in_layer| is the size in layer space dimensions surrounding
+  // opaque. |size_in_context| is the size in the |context|'s space surrounding
   // everything that's visible.
   CompositingRecorder(const PaintContext& context,
-                      const gfx::Size& size_in_layer,
+                      const gfx::Size& size_in_context,
                       uint8_t alpha);
   ~CompositingRecorder();
 
diff --git a/ui/compositor/paint_cache.cc b/ui/compositor/paint_cache.cc
index b4db1ab3b..e9de88d1 100644
--- a/ui/compositor/paint_cache.cc
+++ b/ui/compositor/paint_cache.cc
@@ -16,11 +16,11 @@
 }
 
 bool PaintCache::UseCache(const PaintContext& context,
-                          const gfx::Size& size_in_layer) {
+                          const gfx::Size& size_in_context) {
   if (!has_cache_)
     return false;
   DCHECK(context.list_);
-  gfx::Rect bounds_in_layer = context.ToLayerSpaceBounds(size_in_layer);
+  gfx::Rect bounds_in_layer = context.ToLayerSpaceBounds(size_in_context);
   auto* item = context.list_->CreateAndAppendItem<cc::DrawingDisplayItem>(
       bounds_in_layer);
   display_item_.CloneTo(item);
diff --git a/ui/compositor/paint_cache.h b/ui/compositor/paint_cache.h
index bb8159a..5161127 100644
--- a/ui/compositor/paint_cache.h
+++ b/ui/compositor/paint_cache.h
@@ -24,7 +24,7 @@
   // painting output into the PaintContext. If it returns false, the caller
   // needs to do the work of painting, which can be stored into the PaintCache
   // to be used next time.
-  bool UseCache(const PaintContext& context, const gfx::Size& size_in_layer);
+  bool UseCache(const PaintContext& context, const gfx::Size& size_in_context);
 
  private:
   // Only PaintRecorder can modify these.
diff --git a/ui/compositor/paint_context.cc b/ui/compositor/paint_context.cc
index 2966676..f13db93 100644
--- a/ui/compositor/paint_context.cc
+++ b/ui/compositor/paint_context.cc
@@ -55,8 +55,8 @@
 }
 
 gfx::Rect PaintContext::ToLayerSpaceBounds(
-    const gfx::Size& size_in_layer) const {
-  return gfx::Rect(size_in_layer) + offset_;
+    const gfx::Size& size_in_context) const {
+  return gfx::Rect(size_in_context) + offset_;
 }
 
 gfx::Rect PaintContext::ToLayerSpaceRect(const gfx::Rect& rect) const {
diff --git a/ui/compositor/paint_context.h b/ui/compositor/paint_context.h
index 9d42b55..afa1426 100644
--- a/ui/compositor/paint_context.h
+++ b/ui/compositor/paint_context.h
@@ -82,7 +82,7 @@
 
   // Returns a rect with the given size in the space of the context's
   // containing layer.
-  gfx::Rect ToLayerSpaceBounds(const gfx::Size& size_in_layer) const;
+  gfx::Rect ToLayerSpaceBounds(const gfx::Size& size_in_context) const;
 
   // Returns the given rect translated by the layer space offset.
   gfx::Rect ToLayerSpaceRect(const gfx::Rect& rect) const;
diff --git a/ui/compositor/transform_recorder.cc b/ui/compositor/transform_recorder.cc
index 5eb4038..77448fd 100644
--- a/ui/compositor/transform_recorder.cc
+++ b/ui/compositor/transform_recorder.cc
@@ -10,11 +10,8 @@
 
 namespace ui {
 
-TransformRecorder::TransformRecorder(const PaintContext& context,
-                                     const gfx::Size& size_in_layer)
-    : context_(context),
-      bounds_in_layer_(context.ToLayerSpaceBounds(size_in_layer)),
-      transformed_(false) {}
+TransformRecorder::TransformRecorder(const PaintContext& context)
+    : context_(context), transformed_(false) {}
 
 TransformRecorder::~TransformRecorder() {
   if (transformed_)
@@ -22,8 +19,10 @@
         bounds_in_layer_);
 }
 
-void TransformRecorder::Transform(const gfx::Transform& transform) {
+void TransformRecorder::Transform(const gfx::Transform& transform,
+                                  const gfx::Size& size_in_context) {
   DCHECK(!transformed_);
+  bounds_in_layer_ = context_.ToLayerSpaceBounds(size_in_context);
   auto* item = context_.list_->CreateAndAppendItem<cc::TransformDisplayItem>(
       bounds_in_layer_);
   item->SetNew(transform);
diff --git a/ui/compositor/transform_recorder.h b/ui/compositor/transform_recorder.h
index b7c95a83..c02738e8 100644
--- a/ui/compositor/transform_recorder.h
+++ b/ui/compositor/transform_recorder.h
@@ -25,20 +25,20 @@
 // A class to provide scoped transforms of painting to a DisplayItemList. The
 // transform provided will be applied to any DisplayItems added to the
 // DisplayItemList while this object is alive. In other words, any nested
-// PaintRecorders or other TransformRecorders will be transformed.
+// recorders will be transformed.
 class COMPOSITOR_EXPORT TransformRecorder {
  public:
-  // |size_in_layer| is the size in layer space dimensions surrounding
-  // everything that's visible.
-  TransformRecorder(const PaintContext& context,
-                    const gfx::Size& size_in_layer);
+  explicit TransformRecorder(const PaintContext& context);
   ~TransformRecorder();
 
-  void Transform(const gfx::Transform& transform);
+  // |size_in_context| is the size in the paint context's space surrounding
+  // everything that's visible.
+  void Transform(const gfx::Transform& transform,
+                 const gfx::Size& size_in_context);
 
  private:
   const PaintContext& context_;
-  const gfx::Rect bounds_in_layer_;
+  gfx::Rect bounds_in_layer_;
   bool transformed_;
 
   DISALLOW_COPY_AND_ASSIGN(TransformRecorder);
diff --git a/ui/gfx/render_text.cc b/ui/gfx/render_text.cc
index 27c9e5ad..07d0fb3 100644
--- a/ui/gfx/render_text.cc
+++ b/ui/gfx/render_text.cc
@@ -93,16 +93,18 @@
   return static_cast<SkTypeface::Style>(skia_style);
 }
 
+int round(float value) {
+  return static_cast<int>(floor(value + 0.5f));
+}
+
 // Given |font| and |display_width|, returns the width of the fade gradient.
 int CalculateFadeGradientWidth(const FontList& font_list, int display_width) {
-  // Fade in/out about 2.5 characters of the beginning/end of the string.
-  // The .5 here is helpful if one of the characters is a space.
-  // Use a quarter of the display width if the display width is very short.
-  const int average_character_width = font_list.GetExpectedTextWidth(1);
-  const double gradient_width = std::min(average_character_width * 2.5,
-                                         display_width / 4.0);
-  DCHECK_GE(gradient_width, 0.0);
-  return static_cast<int>(floor(gradient_width + 0.5));
+  // Fade in/out about 3 characters of the beginning/end of the string.
+  // Use a 1/3 of the display width if the display width is very short.
+  const int narrow_width = font_list.GetExpectedTextWidth(3);
+  const int gradient_width = std::min(narrow_width, round(display_width / 3.f));
+  DCHECK_GE(gradient_width, 0);
+  return gradient_width;
 }
 
 // Appends to |positions| and |colors| values corresponding to the fade over
@@ -130,12 +132,22 @@
 
 // Creates a SkShader to fade the text, with |left_part| specifying the left
 // fade effect, if any, and |right_part| specifying the right fade effect.
-skia::RefPtr<SkShader> CreateFadeShader(const Rect& text_rect,
+skia::RefPtr<SkShader> CreateFadeShader(const FontList& font_list,
+                                        const Rect& text_rect,
                                         const Rect& left_part,
                                         const Rect& right_part,
                                         SkColor color) {
-  // Fade alpha of 51/255 corresponds to a fade of 0.2 of the original color.
-  const SkColor fade_color = SkColorSetA(color, 51);
+  // In general, fade down to 0 alpha.  But when the available width is less
+  // than four characters, linearly ramp up the fade target alpha to as high as
+  // 20% at zero width.  This allows the user to see the last faded characters a
+  // little better when there are only a few characters shown.
+  const float width_fraction =
+      text_rect.width() / static_cast<float>(font_list.GetExpectedTextWidth(4));
+  const SkAlpha kAlphaAtZeroWidth = 51;
+  const SkAlpha alpha = (width_fraction < 1) ?
+      static_cast<SkAlpha>(round((1 - width_fraction) * kAlphaAtZeroWidth)) : 0;
+  const SkColor fade_color = SkColorSetA(color, alpha);
+
   std::vector<SkScalar> positions;
   std::vector<SkColor> colors;
 
@@ -1209,8 +1221,9 @@
   text_rect.Inset(GetAlignmentOffset(0).x(), 0, 0, 0);
 
   // TODO(msw): Use the actual text colors corresponding to each faded part.
-  skia::RefPtr<SkShader> shader = CreateFadeShader(
-      text_rect, left_part, right_part, colors_.breaks().front().second);
+  skia::RefPtr<SkShader> shader =
+      CreateFadeShader(font_list(), text_rect, left_part, right_part,
+                       colors_.breaks().front().second);
   if (shader)
     renderer->SetShader(shader.get());
 }
diff --git a/ui/gl/BUILD.gn b/ui/gl/BUILD.gn
index 33a648d8..dda16eec 100644
--- a/ui/gl/BUILD.gn
+++ b/ui/gl/BUILD.gn
@@ -59,6 +59,8 @@
     "gl_fence_nv.h",
     "gl_gl_api_implementation.cc",
     "gl_gl_api_implementation.h",
+    "gl_helper.cc",
+    "gl_helper.h",
     "gl_image.h",
     "gl_image_memory.cc",
     "gl_image_memory.h",
@@ -350,6 +352,10 @@
     sources += [ "gl_image_ozone_native_pixmap_unittest.cc" ]
   }
 
+  if (is_mac) {
+    sources += [ "gl_image_io_surface_unittest.cc" ]
+  }
+
   include_dirs = [ "//third_party/khronos" ]
 
   deps = [
diff --git a/ui/gl/generate_bindings.py b/ui/gl/generate_bindings.py
index d5019b8b..c1d08a0 100755
--- a/ui/gl/generate_bindings.py
+++ b/ui/gl/generate_bindings.py
@@ -79,12 +79,19 @@
   'arguments': 'GLenum target, GLuint index, GLuint buffer, GLintptr offset, '
                'GLsizeiptr size', },
 { 'return_type': 'void',
-  'names': ['glBindFragDataLocation'],
+  'versions': [{ 'name': 'glBindFragDataLocation',
+                 'extensions': ['GL_ARB_blend_func_extended'] },
+               { 'name': 'glBindFragDataLocationEXT',
+                 'extensions': ['GL_EXT_blend_func_extended'] }],
   'arguments': 'GLuint program, GLuint colorNumber, const char* name', },
 { 'return_type': 'void',
-  'names': ['glBindFragDataLocationIndexed'],
+  'versions': [{ 'name': 'glBindFragDataLocationIndexed',
+                 'extensions': ['GL_ARB_blend_func_extended'] },
+               { 'name': 'glBindFragDataLocationIndexedEXT',
+                 'extensions': ['GL_EXT_blend_func_extended'] }],
   'arguments':
-      'GLuint program, GLuint colorNumber, GLuint index, const char* name', },
+      'GLuint program, GLuint colorNumber, GLuint index, const char* name',
+},
 { 'return_type': 'void',
   'names': ['glBindFramebufferEXT', 'glBindFramebuffer'],
   'arguments': 'GLenum target, GLuint framebuffer', },
@@ -543,6 +550,12 @@
   'names': ['glGetFloatv'],
   'arguments': 'GLenum pname, GLfloat* params', },
 { 'return_type': 'GLint',
+  'versions': [{'name': 'glGetFragDataIndex',
+                'extensions': ['GL_ARB_blend_func_extended']},
+               {'name': 'glGetFragDataIndexEXT',
+                'extensions': ['GL_EXT_blend_func_extended']}],
+  'arguments': 'GLuint program, const char* name', },
+{ 'return_type': 'GLint',
   'versions': [{ 'name': 'glGetFragDataLocation' }],
   'arguments': 'GLuint program, const char* name', },
 { 'return_type': 'void',
diff --git a/ui/gl/gl.gyp b/ui/gl/gl.gyp
index 04221f1e0..903278e 100644
--- a/ui/gl/gl.gyp
+++ b/ui/gl/gl.gyp
@@ -73,6 +73,8 @@
         'gl_fence_nv.h',
         'gl_gl_api_implementation.cc',
         'gl_gl_api_implementation.h',
+        'gl_helper.cc',
+        'gl_helper.h',
         'gl_image.h',
         'gl_image_memory.cc',
         'gl_image_memory.h',
diff --git a/ui/gl/gl_bindings.h b/ui/gl/gl_bindings.h
index b712d64..911cd9f 100644
--- a/ui/gl/gl_bindings.h
+++ b/ui/gl/gl_bindings.h
@@ -135,6 +135,9 @@
 // GL_CHROMIUM_ycbcr_422_image
 #define GL_RGB_YCBCR_422_CHROMIUM                        0x78FB
 
+// GL_CHROMIUM_ycbcr_420v_image
+#define GL_RGB_YCBCR_420V_CHROMIUM 0x78FC
+
 // GL_CHROMIUM_schedule_overlay_plane
 #define GL_OVERLAY_TRANSFORM_NONE_CHROMIUM               0x9245
 #define GL_OVERLAY_TRANSFORM_FLIP_HORIZONTAL_CHROMIUM    0x9246
@@ -331,6 +334,16 @@
 #define GL_FRAGMENT_INPUT_NV 0x936D
 #endif
 
+#ifndef GL_EXT_blend_func_extended
+#define GL_EXT_blend_func_extended 1
+#define GL_SRC_ALPHA_SATURATE_EXT 0x0308
+#define GL_SRC1_ALPHA_EXT 0x8589  // OpenGL 1.5 token value
+#define GL_SRC1_COLOR_EXT 0x88F9
+#define GL_ONE_MINUS_SRC1_COLOR_EXT 0x88FA
+#define GL_ONE_MINUS_SRC1_ALPHA_EXT 0x88FB
+#define GL_MAX_DUAL_SOURCE_DRAW_BUFFERS_EXT 0x88FC
+#endif /* GL_EXT_blend_func_extended */
+
 #define GL_GLEXT_PROTOTYPES 1
 
 #if defined(OS_WIN)
diff --git a/ui/gl/gl_bindings_api_autogen_gl.h b/ui/gl/gl_bindings_api_autogen_gl.h
index 4d86720..93039f6 100644
--- a/ui/gl/gl_bindings_api_autogen_gl.h
+++ b/ui/gl/gl_bindings_api_autogen_gl.h
@@ -344,6 +344,7 @@
 GLenum glGetErrorFn(void) override;
 void glGetFenceivNVFn(GLuint fence, GLenum pname, GLint* params) override;
 void glGetFloatvFn(GLenum pname, GLfloat* params) override;
+GLint glGetFragDataIndexFn(GLuint program, const char* name) override;
 GLint glGetFragDataLocationFn(GLuint program, const char* name) override;
 void glGetFramebufferAttachmentParameterivEXTFn(GLenum target,
                                                 GLenum attachment,
diff --git a/ui/gl/gl_bindings_autogen_gl.cc b/ui/gl/gl_bindings_autogen_gl.cc
index e7482d7d..eabd4ae9 100644
--- a/ui/gl/gl_bindings_autogen_gl.cc
+++ b/ui/gl/gl_bindings_autogen_gl.cc
@@ -202,6 +202,7 @@
   fn.glGetFenceivNVFn = 0;
   fn.glGetFloatvFn =
       reinterpret_cast<glGetFloatvProc>(GetGLProcAddress("glGetFloatv"));
+  fn.glGetFragDataIndexFn = 0;
   fn.glGetFragDataLocationFn = 0;
   fn.glGetFramebufferAttachmentParameterivEXTFn = 0;
   fn.glGetGraphicsResetStatusARBFn = 0;
@@ -481,6 +482,8 @@
       extensions.find("GL_APPLE_fence ") != std::string::npos;
   ext.b_GL_APPLE_vertex_array_object =
       extensions.find("GL_APPLE_vertex_array_object ") != std::string::npos;
+  ext.b_GL_ARB_blend_func_extended =
+      extensions.find("GL_ARB_blend_func_extended ") != std::string::npos;
   ext.b_GL_ARB_draw_buffers =
       extensions.find("GL_ARB_draw_buffers ") != std::string::npos;
   ext.b_GL_ARB_draw_instanced =
@@ -509,6 +512,8 @@
       std::string::npos;
   ext.b_GL_CHROMIUM_glgetstringi_hack =
       extensions.find("GL_CHROMIUM_glgetstringi_hack ") != std::string::npos;
+  ext.b_GL_EXT_blend_func_extended =
+      extensions.find("GL_EXT_blend_func_extended ") != std::string::npos;
   ext.b_GL_EXT_debug_marker =
       extensions.find("GL_EXT_debug_marker ") != std::string::npos;
   ext.b_GL_EXT_direct_state_access =
@@ -525,6 +530,8 @@
       extensions.find("GL_EXT_framebuffer_multisample ") != std::string::npos;
   ext.b_GL_EXT_framebuffer_object =
       extensions.find("GL_EXT_framebuffer_object ") != std::string::npos;
+  ext.b_GL_EXT_gpu_shader4 =
+      extensions.find("GL_EXT_gpu_shader4 ") != std::string::npos;
   ext.b_GL_EXT_map_buffer_range =
       extensions.find("GL_EXT_map_buffer_range ") != std::string::npos;
   ext.b_GL_EXT_multisampled_render_to_texture =
@@ -601,16 +608,23 @@
   }
 
   debug_fn.glBindFragDataLocationFn = 0;
-  if (ver->IsAtLeastGL(3u, 0u)) {
+  if (ver->IsAtLeastGL(3u, 0u) || ext.b_GL_ARB_blend_func_extended) {
     fn.glBindFragDataLocationFn = reinterpret_cast<glBindFragDataLocationProc>(
         GetGLProcAddress("glBindFragDataLocation"));
+  } else if (ext.b_GL_EXT_gpu_shader4 || ext.b_GL_EXT_blend_func_extended) {
+    fn.glBindFragDataLocationFn = reinterpret_cast<glBindFragDataLocationProc>(
+        GetGLProcAddress("glBindFragDataLocationEXT"));
   }
 
   debug_fn.glBindFragDataLocationIndexedFn = 0;
-  if (ver->IsAtLeastGL(3u, 3u)) {
+  if (ver->IsAtLeastGL(3u, 3u) || ext.b_GL_ARB_blend_func_extended) {
     fn.glBindFragDataLocationIndexedFn =
         reinterpret_cast<glBindFragDataLocationIndexedProc>(
             GetGLProcAddress("glBindFragDataLocationIndexed"));
+  } else if (ext.b_GL_EXT_blend_func_extended) {
+    fn.glBindFragDataLocationIndexedFn =
+        reinterpret_cast<glBindFragDataLocationIndexedProc>(
+            GetGLProcAddress("glBindFragDataLocationIndexedEXT"));
   }
 
   debug_fn.glBindFramebufferEXTFn = 0;
@@ -1157,6 +1171,15 @@
         GetGLProcAddress("glGetFenceivNV"));
   }
 
+  debug_fn.glGetFragDataIndexFn = 0;
+  if (ver->IsAtLeastGL(3u, 3u) || ext.b_GL_ARB_blend_func_extended) {
+    fn.glGetFragDataIndexFn = reinterpret_cast<glGetFragDataIndexProc>(
+        GetGLProcAddress("glGetFragDataIndex"));
+  } else if (ext.b_GL_EXT_blend_func_extended) {
+    fn.glGetFragDataIndexFn = reinterpret_cast<glGetFragDataIndexProc>(
+        GetGLProcAddress("glGetFragDataIndexEXT"));
+  }
+
   debug_fn.glGetFragDataLocationFn = 0;
   if (ver->IsAtLeastGL(3u, 0u) || ver->IsAtLeastGLES(3u, 0u)) {
     fn.glGetFragDataLocationFn = reinterpret_cast<glGetFragDataLocationProc>(
@@ -3188,6 +3211,15 @@
   g_driver_gl.debug_fn.glGetFloatvFn(pname, params);
 }
 
+static GLint GL_BINDING_CALL Debug_glGetFragDataIndex(GLuint program,
+                                                      const char* name) {
+  GL_SERVICE_LOG("glGetFragDataIndex"
+                 << "(" << program << ", " << name << ")");
+  GLint result = g_driver_gl.debug_fn.glGetFragDataIndexFn(program, name);
+  GL_SERVICE_LOG("GL_RESULT: " << result);
+  return result;
+}
+
 static GLint GL_BINDING_CALL Debug_glGetFragDataLocation(GLuint program,
                                                          const char* name) {
   GL_SERVICE_LOG("glGetFragDataLocation"
@@ -5591,6 +5623,10 @@
     debug_fn.glGetFloatvFn = fn.glGetFloatvFn;
     fn.glGetFloatvFn = Debug_glGetFloatv;
   }
+  if (!debug_fn.glGetFragDataIndexFn) {
+    debug_fn.glGetFragDataIndexFn = fn.glGetFragDataIndexFn;
+    fn.glGetFragDataIndexFn = Debug_glGetFragDataIndex;
+  }
   if (!debug_fn.glGetFragDataLocationFn) {
     debug_fn.glGetFragDataLocationFn = fn.glGetFragDataLocationFn;
     fn.glGetFragDataLocationFn = Debug_glGetFragDataLocation;
@@ -7103,6 +7139,10 @@
   driver_->fn.glGetFloatvFn(pname, params);
 }
 
+GLint GLApiBase::glGetFragDataIndexFn(GLuint program, const char* name) {
+  return driver_->fn.glGetFragDataIndexFn(program, name);
+}
+
 GLint GLApiBase::glGetFragDataLocationFn(GLuint program, const char* name) {
   return driver_->fn.glGetFragDataLocationFn(program, name);
 }
@@ -9104,6 +9144,11 @@
   gl_api_->glGetFloatvFn(pname, params);
 }
 
+GLint TraceGLApi::glGetFragDataIndexFn(GLuint program, const char* name) {
+  TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetFragDataIndex")
+  return gl_api_->glGetFragDataIndexFn(program, name);
+}
+
 GLint TraceGLApi::glGetFragDataLocationFn(GLuint program, const char* name) {
   TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetFragDataLocation")
   return gl_api_->glGetFragDataLocationFn(program, name);
@@ -11415,6 +11460,14 @@
   LOG(ERROR) << "Trying to call glGetFloatv() without current GL context";
 }
 
+GLint NoContextGLApi::glGetFragDataIndexFn(GLuint program, const char* name) {
+  NOTREACHED()
+      << "Trying to call glGetFragDataIndex() without current GL context";
+  LOG(ERROR)
+      << "Trying to call glGetFragDataIndex() without current GL context";
+  return 0;
+}
+
 GLint NoContextGLApi::glGetFragDataLocationFn(GLuint program,
                                               const char* name) {
   NOTREACHED()
diff --git a/ui/gl/gl_bindings_autogen_gl.h b/ui/gl/gl_bindings_autogen_gl.h
index 457c5e4..c568d21 100644
--- a/ui/gl/gl_bindings_autogen_gl.h
+++ b/ui/gl/gl_bindings_autogen_gl.h
@@ -401,6 +401,8 @@
                                                   GLenum pname,
                                                   GLint* params);
 typedef void(GL_BINDING_CALL* glGetFloatvProc)(GLenum pname, GLfloat* params);
+typedef GLint(GL_BINDING_CALL* glGetFragDataIndexProc)(GLuint program,
+                                                       const char* name);
 typedef GLint(GL_BINDING_CALL* glGetFragDataLocationProc)(GLuint program,
                                                           const char* name);
 typedef void(GL_BINDING_CALL* glGetFramebufferAttachmentParameterivEXTProc)(
@@ -1031,6 +1033,7 @@
   bool b_GL_ANGLE_translated_shader_source;
   bool b_GL_APPLE_fence;
   bool b_GL_APPLE_vertex_array_object;
+  bool b_GL_ARB_blend_func_extended;
   bool b_GL_ARB_draw_buffers;
   bool b_GL_ARB_draw_instanced;
   bool b_GL_ARB_get_program_binary;
@@ -1045,6 +1048,7 @@
   bool b_GL_ARB_vertex_array_object;
   bool b_GL_CHROMIUM_gles_depth_binding_hack;
   bool b_GL_CHROMIUM_glgetstringi_hack;
+  bool b_GL_EXT_blend_func_extended;
   bool b_GL_EXT_debug_marker;
   bool b_GL_EXT_direct_state_access;
   bool b_GL_EXT_discard_framebuffer;
@@ -1053,6 +1057,7 @@
   bool b_GL_EXT_framebuffer_blit;
   bool b_GL_EXT_framebuffer_multisample;
   bool b_GL_EXT_framebuffer_object;
+  bool b_GL_EXT_gpu_shader4;
   bool b_GL_EXT_map_buffer_range;
   bool b_GL_EXT_multisampled_render_to_texture;
   bool b_GL_EXT_occlusion_query_boolean;
@@ -1204,6 +1209,7 @@
   glGetErrorProc glGetErrorFn;
   glGetFenceivNVProc glGetFenceivNVFn;
   glGetFloatvProc glGetFloatvFn;
+  glGetFragDataIndexProc glGetFragDataIndexFn;
   glGetFragDataLocationProc glGetFragDataLocationFn;
   glGetFramebufferAttachmentParameterivEXTProc
       glGetFramebufferAttachmentParameterivEXTFn;
@@ -1740,6 +1746,7 @@
   virtual GLenum glGetErrorFn(void) = 0;
   virtual void glGetFenceivNVFn(GLuint fence, GLenum pname, GLint* params) = 0;
   virtual void glGetFloatvFn(GLenum pname, GLfloat* params) = 0;
+  virtual GLint glGetFragDataIndexFn(GLuint program, const char* name) = 0;
   virtual GLint glGetFragDataLocationFn(GLuint program, const char* name) = 0;
   virtual void glGetFramebufferAttachmentParameterivEXTFn(GLenum target,
                                                           GLenum attachment,
@@ -2459,6 +2466,7 @@
 #define glGetError ::gfx::g_current_gl_context->glGetErrorFn
 #define glGetFenceivNV ::gfx::g_current_gl_context->glGetFenceivNVFn
 #define glGetFloatv ::gfx::g_current_gl_context->glGetFloatvFn
+#define glGetFragDataIndex ::gfx::g_current_gl_context->glGetFragDataIndexFn
 #define glGetFragDataLocation \
   ::gfx::g_current_gl_context->glGetFragDataLocationFn
 #define glGetFramebufferAttachmentParameterivEXT \
diff --git a/ui/gl/gl_bindings_autogen_mock.cc b/ui/gl/gl_bindings_autogen_mock.cc
index b356561..43baa49 100644
--- a/ui/gl/gl_bindings_autogen_mock.cc
+++ b/ui/gl/gl_bindings_autogen_mock.cc
@@ -101,6 +101,14 @@
 }
 
 void GL_BINDING_CALL
+MockGLInterface::Mock_glBindFragDataLocationEXT(GLuint program,
+                                                GLuint colorNumber,
+                                                const char* name) {
+  MakeFunctionUnique("glBindFragDataLocationEXT");
+  interface_->BindFragDataLocation(program, colorNumber, name);
+}
+
+void GL_BINDING_CALL
 MockGLInterface::Mock_glBindFragDataLocationIndexed(GLuint program,
                                                     GLuint colorNumber,
                                                     GLuint index,
@@ -110,6 +118,15 @@
 }
 
 void GL_BINDING_CALL
+MockGLInterface::Mock_glBindFragDataLocationIndexedEXT(GLuint program,
+                                                       GLuint colorNumber,
+                                                       GLuint index,
+                                                       const char* name) {
+  MakeFunctionUnique("glBindFragDataLocationIndexedEXT");
+  interface_->BindFragDataLocationIndexed(program, colorNumber, index, name);
+}
+
+void GL_BINDING_CALL
 MockGLInterface::Mock_glBindFramebuffer(GLenum target, GLuint framebuffer) {
   MakeFunctionUnique("glBindFramebuffer");
   interface_->BindFramebufferEXT(target, framebuffer);
@@ -1188,6 +1205,18 @@
 }
 
 GLint GL_BINDING_CALL
+MockGLInterface::Mock_glGetFragDataIndex(GLuint program, const char* name) {
+  MakeFunctionUnique("glGetFragDataIndex");
+  return interface_->GetFragDataIndex(program, name);
+}
+
+GLint GL_BINDING_CALL
+MockGLInterface::Mock_glGetFragDataIndexEXT(GLuint program, const char* name) {
+  MakeFunctionUnique("glGetFragDataIndexEXT");
+  return interface_->GetFragDataIndex(program, name);
+}
+
+GLint GL_BINDING_CALL
 MockGLInterface::Mock_glGetFragDataLocation(GLuint program, const char* name) {
   MakeFunctionUnique("glGetFragDataLocation");
   return interface_->GetFragDataLocation(program, name);
@@ -2857,8 +2886,12 @@
     return reinterpret_cast<void*>(Mock_glBindBufferRange);
   if (strcmp(name, "glBindFragDataLocation") == 0)
     return reinterpret_cast<void*>(Mock_glBindFragDataLocation);
+  if (strcmp(name, "glBindFragDataLocationEXT") == 0)
+    return reinterpret_cast<void*>(Mock_glBindFragDataLocationEXT);
   if (strcmp(name, "glBindFragDataLocationIndexed") == 0)
     return reinterpret_cast<void*>(Mock_glBindFragDataLocationIndexed);
+  if (strcmp(name, "glBindFragDataLocationIndexedEXT") == 0)
+    return reinterpret_cast<void*>(Mock_glBindFragDataLocationIndexedEXT);
   if (strcmp(name, "glBindFramebuffer") == 0)
     return reinterpret_cast<void*>(Mock_glBindFramebuffer);
   if (strcmp(name, "glBindFramebufferEXT") == 0)
@@ -3149,6 +3182,10 @@
     return reinterpret_cast<void*>(Mock_glGetFenceivNV);
   if (strcmp(name, "glGetFloatv") == 0)
     return reinterpret_cast<void*>(Mock_glGetFloatv);
+  if (strcmp(name, "glGetFragDataIndex") == 0)
+    return reinterpret_cast<void*>(Mock_glGetFragDataIndex);
+  if (strcmp(name, "glGetFragDataIndexEXT") == 0)
+    return reinterpret_cast<void*>(Mock_glGetFragDataIndexEXT);
   if (strcmp(name, "glGetFragDataLocation") == 0)
     return reinterpret_cast<void*>(Mock_glGetFragDataLocation);
   if (strcmp(name, "glGetFramebufferAttachmentParameteriv") == 0)
diff --git a/ui/gl/gl_bindings_autogen_mock.h b/ui/gl/gl_bindings_autogen_mock.h
index f97521e..52d4034 100644
--- a/ui/gl/gl_bindings_autogen_mock.h
+++ b/ui/gl/gl_bindings_autogen_mock.h
@@ -30,11 +30,19 @@
 static void GL_BINDING_CALL Mock_glBindFragDataLocation(GLuint program,
                                                         GLuint colorNumber,
                                                         const char* name);
+static void GL_BINDING_CALL Mock_glBindFragDataLocationEXT(GLuint program,
+                                                           GLuint colorNumber,
+                                                           const char* name);
 static void GL_BINDING_CALL
 Mock_glBindFragDataLocationIndexed(GLuint program,
                                    GLuint colorNumber,
                                    GLuint index,
                                    const char* name);
+static void GL_BINDING_CALL
+Mock_glBindFragDataLocationIndexedEXT(GLuint program,
+                                      GLuint colorNumber,
+                                      GLuint index,
+                                      const char* name);
 static void GL_BINDING_CALL Mock_glBindFramebuffer(GLenum target,
                                                    GLuint framebuffer);
 static void GL_BINDING_CALL Mock_glBindFramebufferEXT(GLenum target,
@@ -447,6 +455,10 @@
                                                 GLenum pname,
                                                 GLint* params);
 static void GL_BINDING_CALL Mock_glGetFloatv(GLenum pname, GLfloat* params);
+static GLint GL_BINDING_CALL Mock_glGetFragDataIndex(GLuint program,
+                                                     const char* name);
+static GLint GL_BINDING_CALL Mock_glGetFragDataIndexEXT(GLuint program,
+                                                        const char* name);
 static GLint GL_BINDING_CALL Mock_glGetFragDataLocation(GLuint program,
                                                         const char* name);
 static void GL_BINDING_CALL
diff --git a/ui/gl/gl_enums_implementation_autogen.h b/ui/gl/gl_enums_implementation_autogen.h
index a4812cb..a7e984a 100644
--- a/ui/gl/gl_enums_implementation_autogen.h
+++ b/ui/gl/gl_enums_implementation_autogen.h
@@ -649,9 +649,18 @@
         0x8B6A, "GL_FLOAT_MAT4x3_NV",
     },
     {
+        0x88FA, "GL_ONE_MINUS_SRC1_COLOR_EXT",
+    },
+    {
         0x93D0, "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR",
     },
     {
+        0x88FC, "GL_MAX_DUAL_SOURCE_DRAW_BUFFERS_EXT",
+    },
+    {
+        0x78FC, "GL_RGB_YCBCR_420V_CHROMIUM",
+    },
+    {
         0x9143, "GL_MAX_DEBUG_MESSAGE_LENGTH_KHR",
     },
     {
@@ -829,6 +838,9 @@
         0x83F0, "GL_COMPRESSED_RGB_S3TC_DXT1_EXT",
     },
     {
+        0x88F9, "GL_SRC1_COLOR_EXT",
+    },
+    {
         0x8D6A, "GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT",
     },
     {
@@ -2119,6 +2131,9 @@
         0x8519, "GL_TEXTURE_CUBE_MAP_POSITIVE_Z",
     },
     {
+        0x88FB, "GL_ONE_MINUS_SRC1_ALPHA_EXT",
+    },
+    {
         0x8514, "GL_TEXTURE_BINDING_CUBE_MAP",
     },
     {
@@ -2923,6 +2938,9 @@
         0x8C85, "GL_TRANSFORM_FEEDBACK_BUFFER_SIZE",
     },
     {
+        0x8589, "GL_SRC1_ALPHA_EXT",
+    },
+    {
         0x00008000, "GL_COVERAGE_BUFFER_BIT_NV",
     },
     {
diff --git a/ui/gl/gl_helper.cc b/ui/gl/gl_helper.cc
new file mode 100644
index 0000000..afaebad
--- /dev/null
+++ b/ui/gl/gl_helper.cc
@@ -0,0 +1,97 @@
+// 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.
+
+#include "ui/gl/gl_helper.h"
+
+#include <string>
+
+#include "base/logging.h"
+#include "ui/gl/scoped_binders.h"
+
+namespace gfx {
+
+// static
+GLuint GLHelper::CompileShader(GLenum type, const char* src) {
+  GLuint shader = glCreateShader(type);
+  // Load the shader source.
+  glShaderSource(shader, 1, &src, nullptr);
+  // Compile the shader.
+  glCompileShader(shader);
+  return shader;
+}
+
+// static
+GLuint GLHelper::LoadShader(GLenum type, const char* src) {
+  GLuint shader = CompileShader(type, src);
+
+  // Check the compile status.
+  GLint value = 0;
+  glGetShaderiv(shader, GL_COMPILE_STATUS, &value);
+  if (!value) {
+    char buffer[1024];
+    GLsizei length = 0;
+    glGetShaderInfoLog(shader, sizeof(buffer), &length, buffer);
+    std::string log(buffer, length);
+    DCHECK_EQ(1, value) << "Error compiling shader: " << log;
+    glDeleteShader(shader);
+    shader = 0;
+  }
+  return shader;
+}
+
+// static
+GLuint GLHelper::LinkProgram(GLuint vertex_shader, GLuint fragment_shader) {
+  // Create the program object.
+  GLuint program = glCreateProgram();
+  glAttachShader(program, vertex_shader);
+  glAttachShader(program, fragment_shader);
+  // Link the program.
+  glLinkProgram(program);
+  return program;
+}
+
+// static
+GLuint GLHelper::SetupProgram(GLuint vertex_shader, GLuint fragment_shader) {
+  GLuint program = LinkProgram(vertex_shader, fragment_shader);
+  // Check the link status.
+  GLint linked = 0;
+  glGetProgramiv(program, GL_LINK_STATUS, &linked);
+  if (!linked) {
+    char buffer[1024];
+    GLsizei length = 0;
+    glGetProgramInfoLog(program, sizeof(buffer), &length, buffer);
+    std::string log(buffer, length);
+    DCHECK_EQ(1, linked) << "Error linking program: " << log;
+    glDeleteProgram(program);
+    program = 0;
+  }
+  return program;
+}
+
+// static
+GLuint GLHelper::SetupQuadVertexBuffer() {
+  GLuint vertex_buffer = 0;
+  glGenBuffersARB(1, &vertex_buffer);
+  gfx::ScopedBufferBinder buffer_binder(GL_ARRAY_BUFFER, vertex_buffer);
+  GLfloat data[] = {-1.f, -1.f, 1.f, -1.f, -1.f, 1.f, 1.f, 1.f};
+  glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW);
+  return vertex_buffer;
+}
+
+// static
+void GLHelper::DrawQuad(GLuint vertex_buffer) {
+  gfx::ScopedBufferBinder buffer_binder(GL_ARRAY_BUFFER, vertex_buffer);
+  gfx::ScopedVertexAttribArray vertex_attrib_array(0, 2, GL_FLOAT, GL_FALSE,
+                                                   sizeof(GLfloat) * 2, 0);
+  gfx::ScopedCapability disable_blending(GL_BLEND, GL_FALSE);
+  gfx::ScopedCapability disable_culling(GL_CULL_FACE, GL_FALSE);
+  gfx::ScopedCapability disable_dithering(GL_DITHER, GL_FALSE);
+  gfx::ScopedCapability disable_depth_test(GL_DEPTH_TEST, GL_FALSE);
+  gfx::ScopedCapability disable_scissor_test(GL_SCISSOR_TEST, GL_FALSE);
+  gfx::ScopedColorMask color_mask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+
+  glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+}
+
+}  // namespace gfx
diff --git a/ui/gl/gl_helper.h b/ui/gl/gl_helper.h
new file mode 100644
index 0000000..e38ecf1a
--- /dev/null
+++ b/ui/gl/gl_helper.h
@@ -0,0 +1,42 @@
+// 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.
+
+#ifndef UI_GL_GL_HELPER_H_
+#define UI_GL_GL_HELPER_H_
+
+#include "base/basictypes.h"
+#include "ui/gl/gl_bindings.h"
+#include "ui/gl/gl_export.h"
+
+namespace gfx {
+
+class GL_EXPORT GLHelper {
+ public:
+  // Compiles a shader.
+  // Does not check for errors, always returns shader.
+  static GLuint CompileShader(GLenum type, const char* src);
+
+  // Compiles a shader and checks for compilation errors.
+  // Returns shader, 0 on failure.
+  static GLuint LoadShader(GLenum type, const char* src);
+
+  // Attaches 2 shaders and links them to a program.
+  // Does not check for errors, always returns program.
+  static GLuint LinkProgram(GLuint vertex_shader, GLuint fragment_shader);
+
+  // Attaches 2 shaders, links them to a program, and checks for errors.
+  // Returns program, 0 on failure.
+  static GLuint SetupProgram(GLuint vertex_shader, GLuint fragment_shader);
+
+  // Sets up a vertex buffer containing 4 vertices that can be used to draw
+  // a quad as a tri-strip.
+  static GLuint SetupQuadVertexBuffer();
+
+  // Draws a quad to the currently bound frame buffer.
+  static void DrawQuad(GLuint vertex_buffer);
+};
+
+}  // namespace gfx
+
+#endif  // UI_GL_GL_HELPER_H_
diff --git a/ui/gl/gl_image_io_surface.h b/ui/gl/gl_image_io_surface.h
index 186f5a9..623ad21b 100644
--- a/ui/gl/gl_image_io_surface.h
+++ b/ui/gl/gl_image_io_surface.h
@@ -53,6 +53,8 @@
 
   static void SetLayerForWidget(gfx::AcceleratedWidget widget, CALayer* layer);
 
+  static unsigned GetInternalFormatForTesting(gfx::BufferFormat format);
+
  protected:
   ~GLImageIOSurface() override;
 
@@ -64,6 +66,15 @@
   gfx::GenericSharedMemoryId io_surface_id_;
   base::ThreadChecker thread_checker_;
 
+  // GL state to support 420v IOSurface conversion to RGB.
+  unsigned framebuffer_ = 0;
+  unsigned vertex_shader_ = 0;
+  unsigned fragment_shader_ = 0;
+  unsigned program_ = 0;
+  int size_location_ = -1;
+  unsigned vertex_buffer_ = 0;
+  unsigned yuv_textures_[2] = {};
+
   DISALLOW_COPY_AND_ASSIGN(GLImageIOSurface);
 };
 
diff --git a/ui/gl/gl_image_io_surface.mm b/ui/gl/gl_image_io_surface.mm
index dfd8df9..dc03cd7b 100644
--- a/ui/gl/gl_image_io_surface.mm
+++ b/ui/gl/gl_image_io_surface.mm
@@ -8,11 +8,14 @@
 
 #include "base/lazy_instance.h"
 #include "base/mac/foundation_util.h"
+#include "base/strings/stringize_macros.h"
 #include "base/trace_event/memory_allocator_dump.h"
 #include "base/trace_event/memory_dump_manager.h"
 #include "base/trace_event/process_memory_dump.h"
 #include "ui/gl/gl_bindings.h"
 #include "ui/gl/gl_context.h"
+#include "ui/gl/gl_helper.h"
+#include "ui/gl/scoped_binders.h"
 
 // Note that this must be included after gl_bindings.h to avoid conflicts.
 #include <OpenGL/CGLIOSurface.h>
@@ -26,11 +29,42 @@
 using WidgetToLayerMap = std::map<gfx::AcceleratedWidget, CALayer*>;
 base::LazyInstance<WidgetToLayerMap> g_widget_to_layer_map;
 
+// clang-format off
+const char kVertexShader[] =
+STRINGIZE(
+  attribute vec2 a_position;
+  uniform vec2 a_texScale;
+  varying vec2 v_texCoord;
+  void main() {
+    gl_Position = vec4(a_position.x, a_position.y, 0.0, 1.0);
+    v_texCoord = (a_position + vec2(1.0, 1.0)) * 0.5 * a_texScale;
+  }
+);
+
+const char kFragmentShader[] =
+STRINGIZE(
+  uniform sampler2DRect a_y_texture;
+  uniform sampler2DRect a_uv_texture;
+  varying vec2 v_texCoord;
+  void main() {
+    vec3 yuv_adj = vec3(-0.0625, -0.5, -0.5);
+    mat3 yuv_matrix = mat3(vec3(1.164, 1.164, 1.164),
+                           vec3(0.0, -.391, 2.018),
+                           vec3(1.596, -.813, 0.0));
+    vec3 yuv = vec3(
+        texture2DRect(a_y_texture, v_texCoord).r,
+        texture2DRect(a_uv_texture, v_texCoord * 0.5).rg);
+    gl_FragColor = vec4(yuv_matrix * (yuv + yuv_adj), 1.0);
+  }
+);
+// clang-format on
+
 bool ValidInternalFormat(unsigned internalformat) {
   switch (internalformat) {
     case GL_RED:
     case GL_BGRA_EXT:
     case GL_RGB:
+    case GL_RGB_YCBCR_420V_CHROMIUM:
     case GL_RGB_YCBCR_422_CHROMIUM:
     case GL_RGBA:
       return true;
@@ -66,13 +100,14 @@
 GLenum TextureFormat(BufferFormat format) {
   switch (format) {
     case BufferFormat::R_8:
-    case BufferFormat::YUV_420_BIPLANAR:
       return GL_RED;
     case BufferFormat::BGRA_8888:
     case BufferFormat::RGBA_8888:
       return GL_RGBA;
     case BufferFormat::UYVY_422:
       return GL_RGB;
+    case BufferFormat::YUV_420_BIPLANAR:
+      return GL_RGB_YCBCR_420V_CHROMIUM;
     case BufferFormat::ATC:
     case BufferFormat::ATCIA:
     case BufferFormat::DXT1:
@@ -93,14 +128,12 @@
 GLenum DataFormat(BufferFormat format) {
   switch (format) {
     case BufferFormat::R_8:
-    case BufferFormat::YUV_420_BIPLANAR:
       return GL_RED;
     case BufferFormat::BGRA_8888:
     case BufferFormat::RGBA_8888:
       return GL_BGRA;
     case BufferFormat::UYVY_422:
       return GL_YCBCR_422_APPLE;
-      break;
     case BufferFormat::ATC:
     case BufferFormat::ATCIA:
     case BufferFormat::DXT1:
@@ -110,6 +143,7 @@
     case BufferFormat::RGBX_8888:
     case BufferFormat::BGRX_8888:
     case BufferFormat::YUV_420:
+    case BufferFormat::YUV_420_BIPLANAR:
       NOTREACHED();
       return 0;
   }
@@ -121,7 +155,6 @@
 GLenum DataType(BufferFormat format) {
   switch (format) {
     case BufferFormat::R_8:
-    case BufferFormat::YUV_420_BIPLANAR:
       return GL_UNSIGNED_BYTE;
     case BufferFormat::BGRA_8888:
     case BufferFormat::RGBA_8888:
@@ -138,6 +171,7 @@
     case BufferFormat::RGBX_8888:
     case BufferFormat::BGRX_8888:
     case BufferFormat::YUV_420:
+    case BufferFormat::YUV_420_BIPLANAR:
       NOTREACHED();
       return 0;
   }
@@ -183,6 +217,14 @@
 
 void GLImageIOSurface::Destroy(bool have_context) {
   DCHECK(thread_checker_.CalledOnValidThread());
+  if (have_context && framebuffer_) {
+    glDeleteProgram(program_);
+    glDeleteShader(vertex_shader_);
+    glDeleteShader(fragment_shader_);
+    glDeleteBuffersARB(1, &vertex_buffer_);
+    glDeleteFramebuffersEXT(1, &framebuffer_);
+    glDeleteTextures(2, yuv_textures_);
+  }
   io_surface_.reset();
 }
 
@@ -190,10 +232,19 @@
   return size_;
 }
 
-unsigned GLImageIOSurface::GetInternalFormat() { return internalformat_; }
+unsigned GLImageIOSurface::GetInternalFormat() {
+  return internalformat_;
+}
 
 bool GLImageIOSurface::BindTexImage(unsigned target) {
   DCHECK(thread_checker_.CalledOnValidThread());
+
+  // YUV_420_BIPLANAR is not supported by BindTexImage.
+  // CopyTexImage is supported by this format as that performs conversion to RGB
+  // as part of the copy operation.
+  if (format_ == BufferFormat::YUV_420_BIPLANAR)
+    return false;
+
   if (target != GL_TEXTURE_RECTANGLE_ARB) {
     // This might be supported in the future. For now, perform strict
     // validation so we know what's going on.
@@ -218,7 +269,96 @@
 }
 
 bool GLImageIOSurface::CopyTexImage(unsigned target) {
-  return false;
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  if (format_ != BufferFormat::YUV_420_BIPLANAR)
+    return false;
+
+  if (target != GL_TEXTURE_2D) {
+    LOG(ERROR) << "YUV_420_BIPLANAR requires TEXTURE_2D target";
+    return false;
+  }
+
+  if (!framebuffer_) {
+    glGenFramebuffersEXT(1, &framebuffer_);
+    vertex_buffer_ = gfx::GLHelper::SetupQuadVertexBuffer();
+    vertex_shader_ = gfx::GLHelper::LoadShader(GL_VERTEX_SHADER, kVertexShader);
+    fragment_shader_ =
+        gfx::GLHelper::LoadShader(GL_FRAGMENT_SHADER, kFragmentShader);
+    program_ = gfx::GLHelper::SetupProgram(vertex_shader_, fragment_shader_);
+    gfx::ScopedUseProgram use_program(program_);
+
+    size_location_ = glGetUniformLocation(program_, "a_texScale");
+    DCHECK_NE(-1, size_location_);
+    int y_sampler_location = glGetUniformLocation(program_, "a_y_texture");
+    DCHECK_NE(-1, y_sampler_location);
+    int uv_sampler_location = glGetUniformLocation(program_, "a_uv_texture");
+    DCHECK_NE(-1, uv_sampler_location);
+
+    glUniform1i(y_sampler_location, 0);
+    glUniform1i(uv_sampler_location, 1);
+
+    glGenTextures(2, yuv_textures_);
+    DCHECK(yuv_textures_[0]);
+    DCHECK(yuv_textures_[1]);
+  }
+
+  CGLContextObj cgl_context =
+      static_cast<CGLContextObj>(gfx::GLContext::GetCurrent()->GetHandle());
+
+  GLint target_texture = 0;
+  glGetIntegerv(GL_TEXTURE_BINDING_2D, &target_texture);
+  DCHECK(target_texture);
+  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, size_.width(), size_.height(), 0,
+               GL_RGB, GL_UNSIGNED_BYTE, nullptr);
+
+  CGLError cgl_error = kCGLNoError;
+  {
+    DCHECK(io_surface_);
+
+    gfx::ScopedActiveTexture active_texture0(GL_TEXTURE0);
+    gfx::ScopedTextureBinder texture_y_binder(GL_TEXTURE_RECTANGLE_ARB,
+                                              yuv_textures_[0]);
+    cgl_error = CGLTexImageIOSurface2D(
+        cgl_context, GL_TEXTURE_RECTANGLE_ARB, GL_RED, size_.width(),
+        size_.height(), GL_RED, GL_UNSIGNED_BYTE, io_surface_.get(), 0);
+    if (cgl_error != kCGLNoError) {
+      LOG(ERROR) << "Error in CGLTexImageIOSurface2D for the Y plane. "
+                 << cgl_error;
+      return false;
+    }
+    {
+      gfx::ScopedActiveTexture active_texture1(GL_TEXTURE1);
+      gfx::ScopedTextureBinder texture_uv_binder(GL_TEXTURE_RECTANGLE_ARB,
+                                                 yuv_textures_[1]);
+      cgl_error = CGLTexImageIOSurface2D(
+          cgl_context, GL_TEXTURE_RECTANGLE_ARB, GL_RG, size_.width() / 2,
+          size_.height() / 2, GL_RG, GL_UNSIGNED_BYTE, io_surface_.get(), 1);
+      if (cgl_error != kCGLNoError) {
+        LOG(ERROR) << "Error in CGLTexImageIOSurface2D for the UV plane. "
+                   << cgl_error;
+        return false;
+      }
+
+      gfx::ScopedFrameBufferBinder framebuffer_binder(framebuffer_);
+      gfx::ScopedViewport viewport(0, 0, size_.width(), size_.height());
+      glViewport(0, 0, size_.width(), size_.height());
+      glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+                                GL_TEXTURE_2D, target_texture, 0);
+      DCHECK_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE),
+                glCheckFramebufferStatusEXT(GL_FRAMEBUFFER));
+
+      gfx::ScopedUseProgram use_program(program_);
+      glUniform2f(size_location_, size_.width(), size_.height());
+
+      gfx::GLHelper::DrawQuad(vertex_buffer_);
+
+      // Detach the output texture from the fbo.
+      glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+                                GL_TEXTURE_2D, 0, 0);
+    }
+  }
+  return true;
 }
 
 bool GLImageIOSurface::CopyTexSubImage(unsigned target,
@@ -268,4 +408,10 @@
     g_widget_to_layer_map.Pointer()->erase(widget);
 }
 
-}  // namespace gfx
+// static
+unsigned GLImageIOSurface::GetInternalFormatForTesting(
+    gfx::BufferFormat format) {
+  DCHECK(ValidFormat(format));
+  return TextureFormat(format);
+}
+}  // namespace gl
diff --git a/ui/gl/gl_image_io_surface_unittest.cc b/ui/gl/gl_image_io_surface_unittest.cc
new file mode 100644
index 0000000..c9ca715b
--- /dev/null
+++ b/ui/gl/gl_image_io_surface_unittest.cc
@@ -0,0 +1,56 @@
+// 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.
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/buffer_format_util.h"
+#include "ui/gfx/mac/io_surface_manager.h"
+#include "ui/gl/gl_image_io_surface.h"
+#include "ui/gl/test/gl_image_test_template.h"
+
+namespace gl {
+namespace {
+
+template <gfx::BufferFormat format>
+class GLImageIOSurfaceTestDelegate {
+ public:
+  scoped_refptr<GLImage> CreateSolidColorImage(const gfx::Size& size,
+                                               const uint8_t color[4]) const {
+    scoped_refptr<GLImageIOSurface> image(new GLImageIOSurface(
+        size, GLImageIOSurface::GetInternalFormatForTesting(format)));
+    IOSurfaceRef surface_ref =
+        gfx::IOSurfaceManager::CreateIOSurface(size, format);
+    IOReturn status = IOSurfaceLock(surface_ref, 0, nullptr);
+    EXPECT_NE(status, kIOReturnCannotLock);
+    for (size_t plane = 0; plane < NumberOfPlanesForBufferFormat(format);
+         ++plane) {
+      void* data = IOSurfaceGetBaseAddressOfPlane(surface_ref, plane);
+      GLImageTestSupport::SetBufferDataToColor(
+          size.width(), size.height(),
+          IOSurfaceGetBytesPerRowOfPlane(surface_ref, plane), plane, format,
+          color, static_cast<uint8_t*>(data));
+    }
+    IOSurfaceUnlock(surface_ref, 0, nullptr);
+
+    bool rv =
+        image->Initialize(surface_ref, gfx::GenericSharedMemoryId(1), format);
+    EXPECT_TRUE(rv);
+
+    return image;
+  }
+};
+
+using GLImageTestTypes = testing::Types<
+    GLImageIOSurfaceTestDelegate<gfx::BufferFormat::RGBA_8888>,
+    GLImageIOSurfaceTestDelegate<gfx::BufferFormat::BGRA_8888>,
+    GLImageIOSurfaceTestDelegate<gfx::BufferFormat::YUV_420_BIPLANAR>>;
+
+INSTANTIATE_TYPED_TEST_CASE_P(GLImageIOSurface, GLImageTest, GLImageTestTypes);
+
+INSTANTIATE_TYPED_TEST_CASE_P(
+    GLImageIOSurface,
+    GLImageCopyTest,
+    GLImageIOSurfaceTestDelegate<gfx::BufferFormat::YUV_420_BIPLANAR>);
+
+}  // namespace
+}  // namespace gl
diff --git a/ui/gl/gl_image_ref_counted_memory_unittest.cc b/ui/gl/gl_image_ref_counted_memory_unittest.cc
index 3bbe6aa..12f4fb8 100644
--- a/ui/gl/gl_image_ref_counted_memory_unittest.cc
+++ b/ui/gl/gl_image_ref_counted_memory_unittest.cc
@@ -23,7 +23,7 @@
     scoped_refptr<base::RefCountedBytes> bytes(new base::RefCountedBytes(data));
     GLImageTestSupport::SetBufferDataToColor(
         size.width(), size.height(),
-        static_cast<int>(RowSizeForBufferFormat(size.width(), format, 0)),
+        static_cast<int>(RowSizeForBufferFormat(size.width(), format, 0)), 0,
         format, color, &bytes->data().front());
     scoped_refptr<GLImageRefCountedMemory> image(new GLImageRefCountedMemory(
         size, gl::GLImageMemory::GetInternalFormatForTesting(format)));
diff --git a/ui/gl/gl_image_shared_memory_unittest.cc b/ui/gl/gl_image_shared_memory_unittest.cc
index da6feac3..f0e88239 100644
--- a/ui/gl/gl_image_shared_memory_unittest.cc
+++ b/ui/gl/gl_image_shared_memory_unittest.cc
@@ -24,7 +24,7 @@
     DCHECK(rv);
     GLImageTestSupport::SetBufferDataToColor(
         size.width(), size.height(),
-        static_cast<int>(RowSizeForBufferFormat(size.width(), format, 0)),
+        static_cast<int>(RowSizeForBufferFormat(size.width(), format, 0)), 0,
         format, color, reinterpret_cast<uint8_t*>(shared_memory.memory()));
     scoped_refptr<gl::GLImageSharedMemory> image(new gl::GLImageSharedMemory(
         size, gl::GLImageMemory::GetInternalFormatForTesting(format)));
@@ -71,7 +71,7 @@
     // Place buffer at a non-zero non-page-aligned offset in shared memory.
     size_t buffer_offset = 3 * base::SysInfo::VMAllocationGranularity() / 2;
     GLImageTestSupport::SetBufferDataToColor(
-        size.width(), size.height(), static_cast<int>(stride),
+        size.width(), size.height(), static_cast<int>(stride), 0,
         gfx::BufferFormat::RGBA_8888, color,
         reinterpret_cast<uint8_t*>(shared_memory.memory()) + buffer_offset);
     scoped_refptr<gl::GLImageSharedMemory> image(
diff --git a/ui/gl/gl_mock_autogen_gl.h b/ui/gl/gl_mock_autogen_gl.h
index 2a34acdf..fff4bc57 100644
--- a/ui/gl/gl_mock_autogen_gl.h
+++ b/ui/gl/gl_mock_autogen_gl.h
@@ -340,6 +340,7 @@
 MOCK_METHOD0(GetError, GLenum());
 MOCK_METHOD3(GetFenceivNV, void(GLuint fence, GLenum pname, GLint* params));
 MOCK_METHOD2(GetFloatv, void(GLenum pname, GLfloat* params));
+MOCK_METHOD2(GetFragDataIndex, GLint(GLuint program, const char* name));
 MOCK_METHOD2(GetFragDataLocation, GLint(GLuint program, const char* name));
 MOCK_METHOD4(
     GetFramebufferAttachmentParameterivEXT,
diff --git a/ui/gl/gl_tests.gyp b/ui/gl/gl_tests.gyp
index cc06887..dfce746 100644
--- a/ui/gl/gl_tests.gyp
+++ b/ui/gl/gl_tests.gyp
@@ -49,6 +49,11 @@
             'glx_api_unittest.cc',
           ],
         }],
+        ['OS == "mac"', {
+          'sources': [
+            'gl_image_io_surface_unittest.cc',
+          ],
+        }],
         ['OS == "win"', {
           'sources': [
             'wgl_api_unittest.cc',
diff --git a/ui/gl/scoped_binders.cc b/ui/gl/scoped_binders.cc
index bb2b290..4480f80 100644
--- a/ui/gl/scoped_binders.cc
+++ b/ui/gl/scoped_binders.cc
@@ -29,6 +29,16 @@
   }
 }
 
+ScopedActiveTexture::ScopedActiveTexture(unsigned int texture)
+    : old_texture_(-1) {
+  glGetIntegerv(GL_ACTIVE_TEXTURE, &old_texture_);
+  glActiveTexture(texture);
+}
+
+ScopedActiveTexture::~ScopedActiveTexture() {
+  glActiveTexture(old_texture_);
+}
+
 ScopedTextureBinder::ScopedTextureBinder(unsigned int target, unsigned int id)
     : state_restorer_(!GLContext::GetCurrent()
                           ? NULL
@@ -47,8 +57,11 @@
       case GL_TEXTURE_EXTERNAL_OES:
         target_getter = GL_TEXTURE_BINDING_EXTERNAL_OES;
         break;
+      case GL_TEXTURE_RECTANGLE_ARB:
+        target_getter = GL_TEXTURE_BINDING_RECTANGLE_ARB;
+        break;
       default:
-        NOTIMPLEMENTED() << "Target not part of OpenGL ES 2.0 spec.";
+        NOTIMPLEMENTED() << " Target not supported.";
     }
     glGetIntegerv(target_getter, &old_id_);
   }
@@ -65,4 +78,102 @@
   }
 }
 
+ScopedUseProgram::ScopedUseProgram(unsigned int program) : old_program_(-1) {
+  glGetIntegerv(GL_CURRENT_PROGRAM, &old_program_);
+  glUseProgram(program);
+}
+
+ScopedUseProgram::~ScopedUseProgram() {
+  glUseProgram(old_program_);
+}
+
+ScopedVertexAttribArray::ScopedVertexAttribArray(unsigned int index,
+                                                 int size,
+                                                 unsigned int type,
+                                                 char normalized,
+                                                 int stride,
+                                                 const void* pointer)
+    : buffer_(0),
+      enabled_(GL_FALSE),
+      index_(index),
+      size_(-1),
+      type_(-1),
+      normalized_(GL_FALSE),
+      stride_(0),
+      pointer_(0) {
+  glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, &buffer_);
+  glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &enabled_);
+  glEnableVertexAttribArray(index);
+
+  glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_SIZE, &size_);
+  glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_TYPE, &type_);
+  glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_NORMALIZED, &normalized_);
+  glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_STRIDE, &stride_);
+  glGetVertexAttribPointerv(index, GL_VERTEX_ATTRIB_ARRAY_POINTER, &pointer_);
+
+  glVertexAttribPointer(index, size, type, normalized, stride, pointer);
+}
+
+ScopedVertexAttribArray::~ScopedVertexAttribArray() {
+  ScopedBufferBinder buffer_binder(GL_ARRAY_BUFFER, buffer_);
+  glVertexAttribPointer(index_, size_, type_, normalized_, stride_, pointer_);
+  if (enabled_ == GL_FALSE) {
+    glDisableVertexAttribArray(index_);
+  }
+}
+
+ScopedBufferBinder::ScopedBufferBinder(unsigned int target, unsigned int id)
+    : target_(target), old_id_(-1) {
+  GLenum target_getter = 0;
+  switch (target) {
+    case GL_ARRAY_BUFFER:
+      target_getter = GL_ARRAY_BUFFER_BINDING;
+      break;
+    default:
+      NOTIMPLEMENTED() << " Target not supported.";
+  }
+  glGetIntegerv(target_getter, &old_id_);
+  glBindBuffer(target_, id);
+}
+
+ScopedBufferBinder::~ScopedBufferBinder() {
+  glBindBuffer(target_, old_id_);
+}
+
+ScopedViewport::ScopedViewport(int x, int y, int width, int height) {
+  glGetIntegerv(GL_VIEWPORT, data_);
+  glViewport(x, y, width, height);
+}
+
+ScopedViewport::~ScopedViewport() {
+  glViewport(data_[0], data_[1], data_[2], data_[3]);
+}
+
+ScopedColorMask::ScopedColorMask(char red, char green, char blue, char alpha) {
+  glGetBooleanv(GL_COLOR_WRITEMASK, colors_);
+  glColorMask(red, green, blue, alpha);
+}
+
+ScopedColorMask::~ScopedColorMask() {
+  glColorMask(colors_[0], colors_[1], colors_[2], colors_[3]);
+}
+
+ScopedCapability::ScopedCapability(unsigned capability, unsigned char enabled)
+    : capability_(capability) {
+  enabled_ = glIsEnabled(capability_);
+  if (enabled == GL_TRUE) {
+    glEnable(capability);
+  } else {
+    glDisable(capability);
+  }
+}
+
+ScopedCapability::~ScopedCapability() {
+  if (enabled_ == GL_TRUE) {
+    glEnable(capability_);
+  } else {
+    glDisable(capability_);
+  }
+}
+
 }  // namespace gfx
diff --git a/ui/gl/scoped_binders.h b/ui/gl/scoped_binders.h
index dab7b31..102e47e 100644
--- a/ui/gl/scoped_binders.h
+++ b/ui/gl/scoped_binders.h
@@ -27,6 +27,17 @@
   DISALLOW_COPY_AND_ASSIGN(ScopedFrameBufferBinder);
 };
 
+class GL_EXPORT ScopedActiveTexture {
+ public:
+  ScopedActiveTexture(unsigned int texture);
+  ~ScopedActiveTexture();
+
+ private:
+  // TODO(dcastagna): Use GLStateRestorer.
+  int old_texture_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedActiveTexture);
+};
 
 class GL_EXPORT ScopedTextureBinder {
  public:
@@ -45,6 +56,103 @@
   DISALLOW_COPY_AND_ASSIGN(ScopedTextureBinder);
 };
 
+class GL_EXPORT ScopedUseProgram {
+ public:
+  ScopedUseProgram(unsigned int program);
+  ~ScopedUseProgram();
+
+ private:
+  // TODO(dcastagna): Use GLStateRestorer.
+  int old_program_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedUseProgram);
+};
+
+class GL_EXPORT ScopedVertexAttribArray {
+ public:
+  ScopedVertexAttribArray(unsigned int index,
+                          int size,
+                          unsigned int type,
+                          char normalized,
+                          int stride,
+                          const void* pointer);
+  ~ScopedVertexAttribArray();
+
+ private:
+  // TODO(dcastagna): Use GLStateRestorer.
+  int buffer_;
+  int enabled_;
+  int index_;
+  int size_;
+  int type_;
+  int normalized_;
+  int stride_;
+  void* pointer_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedVertexAttribArray);
+};
+
+class GL_EXPORT ScopedBufferBinder {
+ public:
+  ScopedBufferBinder(unsigned int target, unsigned int index);
+  ~ScopedBufferBinder();
+
+ private:
+  // TODO(dcastagna): Use GLStateRestorer.
+  int target_;
+  int old_id_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedBufferBinder);
+};
+
+class GL_EXPORT ScopedViewport {
+ public:
+  ScopedViewport(int x, int y, int width, int height);
+  ~ScopedViewport();
+
+ private:
+  int data_[4] = {};
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedViewport);
+};
+
+class GL_EXPORT ScopedVertexAttribPointer {
+ public:
+  ScopedVertexAttribPointer(unsigned index,
+                            int size,
+                            unsigned type,
+                            char normalized,
+                            int stride,
+                            const void* pointer);
+  ~ScopedVertexAttribPointer();
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ScopedVertexAttribPointer);
+};
+
+class GL_EXPORT ScopedColorMask {
+ public:
+  ScopedColorMask(char red, char green, char blue, char alpha);
+  ~ScopedColorMask();
+
+ private:
+  unsigned char colors_[4] = {};
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedColorMask);
+};
+
+class GL_EXPORT ScopedCapability {
+ public:
+  ScopedCapability(unsigned capability, unsigned char enabled);
+  ~ScopedCapability();
+
+ private:
+  unsigned capability_;
+  unsigned char enabled_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedCapability);
+};
+
 }  // namespace gfx
 
 #endif  // UI_GL_SCOPED_BINDERS_H_
diff --git a/ui/gl/test/gl_image_test_support.cc b/ui/gl/test/gl_image_test_support.cc
index 7c964d3f..79996d5e 100644
--- a/ui/gl/test/gl_image_test_support.cc
+++ b/ui/gl/test/gl_image_test_support.cc
@@ -39,11 +39,13 @@
 void GLImageTestSupport::SetBufferDataToColor(int width,
                                               int height,
                                               int stride,
+                                              int plane,
                                               gfx::BufferFormat format,
                                               const uint8_t color[4],
                                               uint8_t* data) {
   switch (format) {
     case gfx::BufferFormat::RGBX_8888:
+      DCHECK_EQ(0, plane);
       for (int y = 0; y < height; ++y) {
         for (int x = 0; x < width; ++x) {
           data[y * stride + x * 4 + 0] = color[0];
@@ -54,6 +56,7 @@
       }
       return;
     case gfx::BufferFormat::RGBA_8888:
+      DCHECK_EQ(0, plane);
       for (int y = 0; y < height; ++y) {
         for (int x = 0; x < width; ++x) {
           data[y * stride + x * 4 + 0] = color[0];
@@ -64,6 +67,7 @@
       }
       return;
     case gfx::BufferFormat::BGRX_8888:
+      DCHECK_EQ(0, plane);
       for (int y = 0; y < height; ++y) {
         for (int x = 0; x < width; ++x) {
           data[y * stride + x * 4 + 0] = color[2];
@@ -74,6 +78,7 @@
       }
       return;
     case gfx::BufferFormat::BGRA_8888:
+      DCHECK_EQ(0, plane);
       for (int y = 0; y < height; ++y) {
         for (int x = 0; x < width; ++x) {
           data[y * stride + x * 4 + 0] = color[2];
@@ -83,6 +88,33 @@
         }
       }
       return;
+    case gfx::BufferFormat::YUV_420_BIPLANAR: {
+      DCHECK_LT(plane, 2);
+      DCHECK_EQ(0, height % 2);
+      DCHECK_EQ(0, width % 2);
+      // These values are used in the transformation from YUV to RGB color
+      // values. They are taken from the following webpage:
+      // http://www.fourcc.org/fccyvrgb.php
+      uint8_t yuv[] = {
+          (0.257 * color[0]) + (0.504 * color[1]) + (0.098 * color[2]) + 16,
+          -(0.148 * color[0]) - (0.291 * color[1]) + (0.439 * color[2]) + 128,
+          (0.439 * color[0]) - (0.368 * color[1]) - (0.071 * color[2]) + 128};
+      if (plane == 0) {
+        for (int y = 0; y < height; ++y) {
+          for (int x = 0; x < width; ++x) {
+            data[stride * y + x] = yuv[0];
+          }
+        }
+      } else {
+        for (int y = 0; y < height / 2; ++y) {
+          for (int x = 0; x < width / 2; ++x) {
+            data[stride * y + x * 2] = yuv[1];
+            data[stride * y + x * 2 + 1] = yuv[2];
+          }
+        }
+      }
+      return;
+    }
     case gfx::BufferFormat::ATC:
     case gfx::BufferFormat::ATCIA:
     case gfx::BufferFormat::DXT1:
@@ -91,7 +123,6 @@
     case gfx::BufferFormat::R_8:
     case gfx::BufferFormat::RGBA_4444:
     case gfx::BufferFormat::UYVY_422:
-    case gfx::BufferFormat::YUV_420_BIPLANAR:
     case gfx::BufferFormat::YUV_420:
       NOTREACHED();
       return;
diff --git a/ui/gl/test/gl_image_test_support.h b/ui/gl/test/gl_image_test_support.h
index de86465..41258fc0 100644
--- a/ui/gl/test/gl_image_test_support.h
+++ b/ui/gl/test/gl_image_test_support.h
@@ -22,6 +22,7 @@
   static void SetBufferDataToColor(int width,
                                    int height,
                                    int stride,
+                                   int plane,
                                    gfx::BufferFormat format,
                                    const uint8_t color[4],
                                    uint8_t* data);
diff --git a/ui/gl/test/gl_image_test_template.h b/ui/gl/test/gl_image_test_template.h
index 799f252..8b146445 100644
--- a/ui/gl/test/gl_image_test_template.h
+++ b/ui/gl/test/gl_image_test_template.h
@@ -17,6 +17,7 @@
 #include "ui/gfx/buffer_types.h"
 #include "ui/gl/gl_bindings.h"
 #include "ui/gl/gl_context.h"
+#include "ui/gl/gl_helper.h"
 #include "ui/gl/gl_image.h"
 #include "ui/gl/gl_implementation.h"
 #include "ui/gl/gl_surface.h"
@@ -89,7 +90,10 @@
 
 TYPED_TEST_P(GLImageCopyTest, CopyTexImage) {
   const gfx::Size image_size(256, 256);
-  const uint8_t image_color[] = {0xff, 0xff, 0, 0xff};
+  // These values are picked so that RGB -> YUV on the CPU converted
+  // back to RGB on the GPU produces the original RGB values without
+  // any error.
+  const uint8_t image_color[] = {0x10, 0x20, 0, 0xff};
   const uint8_t texture_color[] = {0, 0, 0xff, 0xff};
 
   GLuint framebuffer =
@@ -112,7 +116,7 @@
       image_size.width(), image_size.height(),
       static_cast<int>(RowSizeForBufferFormat(image_size.width(),
                                               gfx::BufferFormat::RGBA_8888, 0)),
-      gfx::BufferFormat::RGBA_8888, texture_color, pixels.get());
+      0, gfx::BufferFormat::RGBA_8888, texture_color, pixels.get());
   // Note: This test assume that |image| can be used with GL_TEXTURE_2D but
   // that might not be the case for some GLImage implementations.
   glBindTexture(GL_TEXTURE_2D, texture);
@@ -126,11 +130,10 @@
   // clang-format off
   const char kVertexShader[] = STRINGIZE(
     attribute vec2 a_position;
-    attribute vec2 a_texCoord;
     varying vec2 v_texCoord;
     void main() {
       gl_Position = vec4(a_position.x, a_position.y, 0.0, 1.0);
-      v_texCoord = a_texCoord;
+      v_texCoord = (a_position + vec2(1.0, 1.0)) * 0.5;
     }
   );
   const char kFragmentShader[] = STRINGIZE(
@@ -146,14 +149,14 @@
   // clang-format on
 
   GLuint vertex_shader =
-      GLTestHelper::LoadShader(GL_VERTEX_SHADER, kVertexShader);
+      gfx::GLHelper::LoadShader(GL_VERTEX_SHADER, kVertexShader);
   bool is_gles = gfx::GetGLImplementation() == gfx::kGLImplementationEGLGLES2;
-  GLuint fragment_shader = GLTestHelper::LoadShader(
+  GLuint fragment_shader = gfx::GLHelper::LoadShader(
       GL_FRAGMENT_SHADER,
       base::StringPrintf("%s%s", is_gles ? kShaderFloatPrecision : "",
                          kFragmentShader)
           .c_str());
-  GLuint program = GLTestHelper::SetupProgram(vertex_shader, fragment_shader);
+  GLuint program = gfx::GLHelper::SetupProgram(vertex_shader, fragment_shader);
   EXPECT_NE(program, 0u);
   glUseProgram(program);
 
@@ -161,33 +164,10 @@
   ASSERT_NE(sampler_location, -1);
   glUniform1i(sampler_location, 0);
 
-  // clang-format off
-  static GLfloat vertices[] = {
-    -1.f, -1.f, 0.f, 0.f,
-     1.f, -1.f, 1.f, 0.f,
-    -1.f,  1.f, 0.f, 1.f,
-     1.f,  1.f, 1.f, 1.f
-  };
-  // clang-format on
-
-  GLuint vertex_buffer;
-  glGenBuffersARB(1, &vertex_buffer);
-  glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);
-  glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
-  GLint position_location = glGetAttribLocation(program, "a_position");
-  ASSERT_NE(position_location, -1);
-  glEnableVertexAttribArray(position_location);
-  glVertexAttribPointer(position_location, 2, GL_FLOAT, GL_FALSE,
-                        sizeof(GLfloat) * 4, 0);
-  GLint tex_coord_location = glGetAttribLocation(program, "a_texCoord");
-  EXPECT_NE(tex_coord_location, -1);
-  glEnableVertexAttribArray(tex_coord_location);
-  glVertexAttribPointer(tex_coord_location, 2, GL_FLOAT, GL_FALSE,
-                        sizeof(GLfloat) * 4,
-                        reinterpret_cast<void*>(sizeof(GLfloat) * 2));
-
+  GLuint vertex_buffer = gfx::GLHelper::SetupQuadVertexBuffer();
   // Draw |texture| to viewport and read back pixels to check expectations.
-  glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+  gfx::GLHelper::DrawQuad(vertex_buffer);
+
   GLTestHelper::CheckPixels(0, 0, image_size.width(), image_size.height(),
                             image_color);
 
diff --git a/ui/gl/test/gl_test_helper.cc b/ui/gl/test/gl_test_helper.cc
index 24b9b47..5f462a3 100644
--- a/ui/gl/test/gl_test_helper.cc
+++ b/ui/gl/test/gl_test_helper.cc
@@ -10,7 +10,6 @@
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace gl {
-
 // static
 GLuint GLTestHelper::CreateTexture(GLenum target) {
   // Create the texture object.
@@ -25,65 +24,6 @@
 }
 
 // static
-GLuint GLTestHelper::CompileShader(GLenum type, const char* src) {
-  GLuint shader = glCreateShader(type);
-  // Load the shader source.
-  glShaderSource(shader, 1, &src, nullptr);
-  // Compile the shader.
-  glCompileShader(shader);
-  return shader;
-}
-
-// static
-GLuint GLTestHelper::LoadShader(GLenum type, const char* src) {
-  GLuint shader = CompileShader(type, src);
-
-  // Check the compile status.
-  GLint value = 0;
-  glGetShaderiv(shader, GL_COMPILE_STATUS, &value);
-  if (!value) {
-    char buffer[1024];
-    GLsizei length = 0;
-    glGetShaderInfoLog(shader, sizeof(buffer), &length, buffer);
-    std::string log(buffer, length);
-    EXPECT_EQ(1, value) << "Error compiling shader: " << log;
-    glDeleteShader(shader);
-    shader = 0;
-  }
-  return shader;
-}
-
-// static
-GLuint GLTestHelper::LinkProgram(GLuint vertex_shader, GLuint fragment_shader) {
-  // Create the program object.
-  GLuint program = glCreateProgram();
-  glAttachShader(program, vertex_shader);
-  glAttachShader(program, fragment_shader);
-  // Link the program.
-  glLinkProgram(program);
-  return program;
-}
-
-// static
-GLuint GLTestHelper::SetupProgram(GLuint vertex_shader,
-                                  GLuint fragment_shader) {
-  GLuint program = LinkProgram(vertex_shader, fragment_shader);
-  // Check the link status.
-  GLint linked = 0;
-  glGetProgramiv(program, GL_LINK_STATUS, &linked);
-  if (!linked) {
-    char buffer[1024];
-    GLsizei length = 0;
-    glGetProgramInfoLog(program, sizeof(buffer), &length, buffer);
-    std::string log(buffer, length);
-    EXPECT_EQ(1, linked) << "Error linking program: " << log;
-    glDeleteProgram(program);
-    program = 0;
-  }
-  return program;
-}
-
-// static
 GLuint GLTestHelper::SetupFramebuffer(int width, int height) {
   GLuint color_buffer_texture = CreateTexture(GL_TEXTURE_2D);
   glBindTexture(GL_TEXTURE_2D, color_buffer_texture);
diff --git a/ui/gl/test/gl_test_helper.h b/ui/gl/test/gl_test_helper.h
index ac7be68..98b2e0e 100644
--- a/ui/gl/test/gl_test_helper.h
+++ b/ui/gl/test/gl_test_helper.h
@@ -16,22 +16,6 @@
   // Does not check for errors, always returns texture.
   static GLuint CreateTexture(GLenum target);
 
-  // Compiles a shader.
-  // Does not check for errors, always returns shader.
-  static GLuint CompileShader(GLenum type, const char* src);
-
-  // Compiles a shader and checks for compilation errors.
-  // Returns shader, 0 on failure.
-  static GLuint LoadShader(GLenum type, const char* src);
-
-  // Attaches 2 shaders and links them to a program.
-  // Does not check for errors, always returns program.
-  static GLuint LinkProgram(GLuint vertex_shader, GLuint fragment_shader);
-
-  // Attaches 2 shaders, links them to a program, and checks for errors.
-  // Returns program, 0 on failure.
-  static GLuint SetupProgram(GLuint vertex_shader, GLuint fragment_shader);
-
   // Creates a framebuffer, attaches a color buffer, and checks for errors.
   // Returns framebuffer, 0 on failure.
   static GLuint SetupFramebuffer(int width, int height);
diff --git a/ui/login/display_manager.js b/ui/login/display_manager.js
index e94342a..a945bfef 100644
--- a/ui/login/display_manager.js
+++ b/ui/login/display_manager.js
@@ -59,10 +59,9 @@
   WRONG_HWID_WARNING: 3,
   SUPERVISED_USER_CREATION_FLOW: 4,
   SAML_PASSWORD_CONFIRM: 5,
-  CONSUMER_MANAGEMENT_ENROLLMENT: 6,
-  PASSWORD_CHANGED: 7,
-  ENROLLMENT: 8,
-  ERROR: 9
+  PASSWORD_CHANGED: 6,
+  ENROLLMENT: 7,
+  ERROR: 8
 };
 
 /* Possible UI states of the error screen. */
diff --git a/ui/platform_window/android/platform_ime_controller_android.cc b/ui/platform_window/android/platform_ime_controller_android.cc
index 58a04ec..67c8d32 100644
--- a/ui/platform_window/android/platform_ime_controller_android.cc
+++ b/ui/platform_window/android/platform_ime_controller_android.cc
@@ -28,12 +28,14 @@
 
 void PlatformImeControllerAndroid::UpdateTextInputState(
     const TextInputState& state) {
-  if (java_platform_ime_controller_android_.is_empty())
-    return;
   JNIEnv* env = base::android::AttachCurrentThread();
+  ScopedJavaLocalRef<jobject> scoped_obj =
+      java_platform_ime_controller_android_.get(env);
+  if (scoped_obj.is_null())
+    return;
   Java_PlatformImeControllerAndroid_updateTextInputState(
       env,
-      java_platform_ime_controller_android_.get(env).obj(),
+      scoped_obj.obj(),
       state.type,
       state.flags,
       base::android::ConvertUTF8ToJavaString(env, state.text).obj(),
@@ -44,13 +46,13 @@
 }
 
 void PlatformImeControllerAndroid::SetImeVisibility(bool visible) {
-  if (java_platform_ime_controller_android_.is_empty())
-    return;
   JNIEnv* env = base::android::AttachCurrentThread();
+  ScopedJavaLocalRef<jobject> scoped_obj =
+      java_platform_ime_controller_android_.get(env);
+  if (scoped_obj.is_null())
+    return;
   Java_PlatformImeControllerAndroid_setImeVisibility(
-      env,
-      java_platform_ime_controller_android_.get(env).obj(),
-      visible);
+      env, scoped_obj.obj(), visible);
 }
 
 }  // namespace ui
diff --git a/ui/platform_window/android/platform_window_android.cc b/ui/platform_window/android/platform_window_android.cc
index b9ee0519..0cfdc6bf 100644
--- a/ui/platform_window/android/platform_window_android.cc
+++ b/ui/platform_window/android/platform_window_android.cc
@@ -62,10 +62,11 @@
 PlatformWindowAndroid::~PlatformWindowAndroid() {
   if (window_)
     ReleaseWindow();
-  if (!java_platform_window_android_.is_empty()) {
-    JNIEnv* env = base::android::AttachCurrentThread();
-    Java_PlatformWindowAndroid_detach(
-        env, java_platform_window_android_.get(env).obj());
+  JNIEnv* env = base::android::AttachCurrentThread();
+  ScopedJavaLocalRef<jobject> scoped_obj =
+      java_platform_window_android_.get(env);
+  if (!scoped_obj.is_null()) {
+    Java_PlatformWindowAndroid_detach(env, scoped_obj.obj());
   }
 }
 
diff --git a/ui/platform_window/x11/x11_window.cc b/ui/platform_window/x11/x11_window.cc
index 073fe4da..c84135fa 100644
--- a/ui/platform_window/x11/x11_window.cc
+++ b/ui/platform_window/x11/x11_window.cc
@@ -257,7 +257,9 @@
 
 void X11Window::Restore() {}
 
-void X11Window::SetCursor(PlatformCursor cursor) {}
+void X11Window::SetCursor(PlatformCursor cursor) {
+  XDefineCursor(xdisplay_, xwindow_, cursor);
+}
 
 void X11Window::MoveCursorTo(const gfx::Point& location) {}
 
diff --git a/ui/views/background.cc b/ui/views/background.cc
index 62cdc3b..41e0277 100644
--- a/ui/views/background.cc
+++ b/ui/views/background.cc
@@ -5,13 +5,15 @@
 #include "ui/views/background.h"
 
 #include "base/logging.h"
-#include "skia/ext/skia_utils_win.h"
-#include "third_party/skia/include/core/SkPaint.h"
 #include "ui/gfx/canvas.h"
 #include "ui/gfx/color_utils.h"
 #include "ui/views/painter.h"
 #include "ui/views/view.h"
 
+#if defined(OS_WIN)
+#include "skia/ext/skia_utils_win.h"
+#endif
+
 namespace views {
 
 // SolidBackground is a trivial Background implementation that fills the
diff --git a/ui/views/controls/single_split_view.cc b/ui/views/controls/single_split_view.cc
index fe50141..542d17f 100644
--- a/ui/views/controls/single_split_view.cc
+++ b/ui/views/controls/single_split_view.cc
@@ -4,7 +4,6 @@
 
 #include "ui/views/controls/single_split_view.h"
 
-#include "skia/ext/skia_utils_win.h"
 #include "ui/accessibility/ax_view_state.h"
 #include "ui/base/cursor/cursor.h"
 #include "ui/gfx/canvas.h"
@@ -12,6 +11,10 @@
 #include "ui/views/controls/single_split_view_listener.h"
 #include "ui/views/native_cursor.h"
 
+#if defined(OS_WIN)
+#include "skia/ext/skia_utils_win.h"
+#endif
+
 namespace views {
 
 // static
diff --git a/ui/views/controls/table/table_view.cc b/ui/views/controls/table/table_view.cc
index 7b4d5257..9a282e8 100644
--- a/ui/views/controls/table/table_view.cc
+++ b/ui/views/controls/table/table_view.cc
@@ -542,7 +542,7 @@
                                                   GetRowBounds(i),
                                                   canvas);
     }
-    if (selection_model_.active() == i && HasFocus())
+    if (selection_model_.active() == model_index && HasFocus())
       canvas->DrawFocusRect(GetRowBounds(i));
     for (int j = region.min_column; j < region.max_column; ++j) {
       const gfx::Rect cell_bounds(GetCellBounds(i, j));
diff --git a/ui/views/mus/native_widget_mus.cc b/ui/views/mus/native_widget_mus.cc
index 2402458..4a1d77da 100644
--- a/ui/views/mus/native_widget_mus.cc
+++ b/ui/views/mus/native_widget_mus.cc
@@ -589,7 +589,14 @@
 }
 
 void NativeWidgetMus::SetCursor(gfx::NativeCursor cursor) {
-  // NOTIMPLEMENTED();
+  // TODO(erg): In aura, our incoming cursor is really two
+  // parts. cursor.native_type() is an integer for standard cursors and is all
+  // we support right now. If native_type() == kCursorCustom, than we should
+  // also send an image, but as the cursor code is currently written, the image
+  // is in a platform native format that's already uploaded to the window
+  // server.
+  window_tree_host_->platform_window()->SetCursorById(
+      mus::mojom::Cursor(cursor.native_type()));
 }
 
 bool NativeWidgetMus::IsMouseEventsEnabled() const {
diff --git a/ui/views/mus/platform_window_mus.cc b/ui/views/mus/platform_window_mus.cc
index 132e4b4..5111b705 100644
--- a/ui/views/mus/platform_window_mus.cc
+++ b/ui/views/mus/platform_window_mus.cc
@@ -23,6 +23,7 @@
     : delegate_(delegate),
       mus_window_(mus_window),
       show_state_(mus::mojom::SHOW_STATE_RESTORED),
+      last_cursor_(mus::mojom::CURSOR_NULL),
       has_capture_(false) {
   DCHECK(delegate_);
   DCHECK(mus_window_);
@@ -54,6 +55,17 @@
   mus_window_->SetFocus();
 }
 
+void PlatformWindowMus::SetCursorById(mus::mojom::Cursor cursor) {
+  if (last_cursor_ != cursor) {
+    // The ui::PlatformWindow interface uses ui::PlatformCursor at this level,
+    // instead of ui::Cursor. All of the cursor abstractions in ui right now are
+    // sort of leaky; despite being nominally cross platform, they all drop down
+    // to platform types almost immediately, which makes them unusable as
+    // transport types.
+    mus_window_->SetPredefinedCursor(cursor);
+  }
+}
+
 void PlatformWindowMus::Show() {
   mus_window_->SetVisible(true);
 }
@@ -147,6 +159,13 @@
     delegate_->OnActivationChanged(false);
 }
 
+void PlatformWindowMus::OnWindowPredefinedCursorChanged(
+    mus::Window* window,
+    mus::mojom::Cursor cursor) {
+  DCHECK_EQ(window, mus_window_);
+  last_cursor_ = cursor;
+}
+
 void PlatformWindowMus::OnWindowInputEvent(mus::Window* view,
                                            const mus::mojom::EventPtr& event) {
   scoped_ptr<ui::Event> ui_event(event.To<scoped_ptr<ui::Event>>());
diff --git a/ui/views/mus/platform_window_mus.h b/ui/views/mus/platform_window_mus.h
index 0c16f98..69c6dd3d 100644
--- a/ui/views/mus/platform_window_mus.h
+++ b/ui/views/mus/platform_window_mus.h
@@ -25,6 +25,8 @@
 
   void Activate();
 
+  void SetCursorById(mus::mojom::Cursor cursor);
+
   // ui::PlatformWindow:
   void Show() override;
   void Hide() override;
@@ -53,6 +55,8 @@
                              const gfx::Rect& new_bounds) override;
   void OnWindowFocusChanged(mus::Window* gained_focus,
                             mus::Window* lost_focus) override;
+  void OnWindowPredefinedCursorChanged(mus::Window* window,
+                                       mus::mojom::Cursor cursor) override;
   void OnWindowInputEvent(mus::Window* view,
                           const mus::mojom::EventPtr& event) override;
   void OnWindowSharedPropertyChanged(
@@ -64,6 +68,7 @@
   ui::PlatformWindowDelegate* delegate_;
   mus::Window* mus_window_;
   mus::mojom::ShowState show_state_;
+  mus::mojom::Cursor last_cursor_;
   bool has_capture_;
 
   DISALLOW_COPY_AND_ASSIGN(PlatformWindowMus);
diff --git a/ui/views/view.cc b/ui/views/view.cc
index 4aa6d5a..d2bc11e6 100644
--- a/ui/views/view.cc
+++ b/ui/views/view.cc
@@ -791,10 +791,9 @@
   // rather than relative to its parent.
   bool paint_relative_to_parent = !layer();
 
-  // TODO(wkorman): Rework clip and transform recorders to pass the size in the
-  // individual clip methods rather than in the constructor.
-  ui::ClipRecorder clip_recorder(parent_context,
-                                 parent() ? parent()->size() : size());
+  // TODO(danakj): Rework clip and transform recorder usage here to use
+  // std::optional once we can do so.
+  ui::ClipRecorder clip_recorder(parent_context);
   if (paint_relative_to_parent) {
     // Set the clip rect to the bounds of this View. Note that the X (or left)
     // position we pass to ClipRect takes into consideration whether or not the
@@ -808,7 +807,7 @@
     clip_recorder.ClipRect(clip_rect_in_parent);
   }
 
-  ui::TransformRecorder transform_recorder(context, size());
+  ui::TransformRecorder transform_recorder(context);
   if (paint_relative_to_parent) {
     // Translate the graphics such that 0,0 corresponds to where
     // this View is located relative to its parent.
@@ -817,7 +816,7 @@
     transform_from_parent.Translate(offset_from_parent.x(),
                                     offset_from_parent.y());
     transform_from_parent.PreconcatTransform(GetTransform());
-    transform_recorder.Transform(transform_from_parent);
+    transform_recorder.Transform(transform_from_parent, size());
   }
 
   // Note that the cache is not aware of the offset of the view
diff --git a/ui/views/win/hwnd_message_handler.cc b/ui/views/win/hwnd_message_handler.cc
index 035df76..b5bd8a8 100644
--- a/ui/views/win/hwnd_message_handler.cc
+++ b/ui/views/win/hwnd_message_handler.cc
@@ -2265,9 +2265,6 @@
                                                      WPARAM w_param,
                                                      LPARAM l_param,
                                                      bool track_mouse) {
-  if (!touch_ids_.empty())
-    return 0;
-
   // We handle touch events on Windows Aura. Windows generates synthesized
   // mouse messages in response to touch which we should ignore. However touch
   // messages are only received for the client area. We need to ignore the
@@ -2287,6 +2284,26 @@
       return 0;
   }
 
+  // Windows does not reliably set the touch flag on mouse moves and nc
+  // mouse moves. We also ignore mouse leaves as they are an artificially
+  // generated message in response to the TrackMouseEvents API.
+  // The code below is primarily for validation that we don't receive
+  // other mouse messages while we are in a touch sequence.
+  switch (message) {
+    case WM_MOUSEMOVE:
+    case WM_NCMOUSEMOVE:
+    case WM_MOUSELEAVE:
+    case WM_NCMOUSELEAVE:
+      break;
+
+    default:
+      // Remove this CHECK once we validate that our hypothesis about the above
+      // mouse events being the only ones on which the touch flag is not set
+      // is correct.
+      CHECK(touch_ids_.empty());
+      break;
+  }
+
   // Certain logitech drivers send the WM_MOUSEHWHEEL message to the parent
   // followed by WM_MOUSEWHEEL messages to the child window causing a vertical
   // scroll. We treat these WM_MOUSEWHEEL messages as WM_MOUSEHWHEEL